From f7e2505fc7b007f29b4c61de1cf2337b07e3b589 Mon Sep 17 00:00:00 2001 From: Mike Jerris Date: Mon, 20 Nov 2017 11:30:50 -0500 Subject: [PATCH] cleanup unused --- .gitignore | 14 - debian/copyright | 18 - libs/libblade/.gitignore | 4 - libs/libblade/AUTHORS | 0 libs/libblade/COPYING | 1 - libs/libblade/ChangeLog | 0 libs/libblade/INSTALL | 370 - libs/libblade/Makefile.am | 57 - libs/libblade/NEWS | 0 libs/libblade/README | 26 - libs/libblade/acinclude.m4 | 7 - libs/libblade/bootstrap.sh | 4 - libs/libblade/build/compile | 347 - .../build/config/ac_cflags_gcc_option.m4 | 142 - .../build/config/ac_cflags_sun_option.m4 | 140 - libs/libblade/build/config/ac_gcc_archflag.m4 | 148 - .../libblade/build/config/ac_gcc_x86_cpuid.m4 | 21 - libs/libblade/build/config/ac_prog_gzip.m4 | 9 - libs/libblade/build/config/ac_prog_wget.m4 | 9 - libs/libblade/build/config/ax_cc_maxopt.m4 | 120 - .../build/config/ax_cflags_warn_all_ansi.m4 | 94 - .../build/config/ax_check_compiler_flags.m4 | 26 - .../build/config/ax_compiler_vendor.m4 | 15 - libs/libblade/build/config/sac-openssl.m4 | 49 - libs/libblade/configure.ac | 302 - libs/libblade/flows/flow1.json | 227 - libs/libblade/libblade.pc.in | 11 - libs/libblade/libblade.props | 14 - libs/libblade/libblade.sln | 552 - libs/libblade/libblade.vcxproj | 246 - libs/libblade/libblade.vcxproj.filters | 156 - libs/libblade/src/bencode.c | 2683 - libs/libblade/src/blade.c | 64 - libs/libblade/src/blade_channel.c | 181 - libs/libblade/src/blade_connection.c | 481 - libs/libblade/src/blade_connectionmgr.c | 183 - libs/libblade/src/blade_identity.c | 357 - libs/libblade/src/blade_mastermgr.c | 505 - libs/libblade/src/blade_protocol.c | 289 - libs/libblade/src/blade_restmgr.c | 562 - libs/libblade/src/blade_routemgr.c | 533 - libs/libblade/src/blade_rpc.c | 460 - libs/libblade/src/blade_rpcmgr.c | 364 - libs/libblade/src/blade_session.c | 810 - libs/libblade/src/blade_sessionmgr.c | 338 - libs/libblade/src/blade_stack.c | 2139 - libs/libblade/src/blade_subscription.c | 181 - libs/libblade/src/blade_subscriptionmgr.c | 509 - libs/libblade/src/blade_transport.c | 137 - libs/libblade/src/blade_transport_wss.c | 1206 - libs/libblade/src/blade_transportmgr.c | 233 - libs/libblade/src/blade_tuple.c | 107 - libs/libblade/src/blade_web.c | 674 - libs/libblade/src/dht/ks_dht.c | 3278 - libs/libblade/src/dht/ks_dht_bucket.c | 2004 - libs/libblade/src/dht/ks_dht_datagram.c | 60 - libs/libblade/src/dht/ks_dht_distribute.c | 65 - libs/libblade/src/dht/ks_dht_endpoint.c | 61 - libs/libblade/src/dht/ks_dht_job.c | 136 - libs/libblade/src/dht/ks_dht_message.c | 122 - libs/libblade/src/dht/ks_dht_publish.c | 62 - libs/libblade/src/dht/ks_dht_search.c | 71 - libs/libblade/src/dht/ks_dht_storageitem.c | 214 - libs/libblade/src/dht/ks_dht_transaction.c | 54 - libs/libblade/src/include/blade.h | 90 - libs/libblade/src/include/blade_channel.h | 63 - libs/libblade/src/include/blade_connection.h | 71 - .../src/include/blade_connectionmgr.h | 59 - libs/libblade/src/include/blade_identity.h | 63 - libs/libblade/src/include/blade_mastermgr.h | 65 - libs/libblade/src/include/blade_protocol.h | 68 - libs/libblade/src/include/blade_restmgr.h | 61 - libs/libblade/src/include/blade_routemgr.h | 68 - libs/libblade/src/include/blade_rpc.h | 94 - libs/libblade/src/include/blade_rpcmgr.h | 65 - libs/libblade/src/include/blade_session.h | 82 - libs/libblade/src/include/blade_sessionmgr.h | 65 - libs/libblade/src/include/blade_stack.h | 99 - .../libblade/src/include/blade_subscription.h | 63 - .../src/include/blade_subscriptionmgr.h | 61 - libs/libblade/src/include/blade_transport.h | 58 - .../src/include/blade_transport_wss.h | 55 - .../libblade/src/include/blade_transportmgr.h | 62 - libs/libblade/src/include/blade_tuple.h | 56 - libs/libblade/src/include/blade_types.h | 185 - libs/libblade/src/include/blade_web.h | 80 - libs/libblade/src/include/ks_bencode.h | 730 - libs/libblade/src/include/ks_dht-int.h | 447 - libs/libblade/src/include/ks_dht.h | 596 - libs/libblade/src/include/unqlite.h | 950 - libs/libblade/src/ks_bencode.c | 2698 - libs/libblade/src/unqlite.c | 60240 ---------------- libs/libblade/switchblade/Makefile.am | 11 - libs/libblade/switchblade/restroot/test.lp | 14 - libs/libblade/switchblade/switchblade.c | 181 - libs/libblade/switchblade/switchblade.cfg | 32 - libs/libblade/switchblade/switchblade.vcxproj | 216 - libs/libblade/test/.gitignore | 5 - libs/libblade/test/Makefile.am | 39 - libs/libblade/test/ca/certs/ca.cert.pem | 33 - libs/libblade/test/ca/index.txt | 1 - libs/libblade/test/ca/index.txt.attr | 1 - libs/libblade/test/ca/index.txt.old | 0 .../ca/intermediate/certs/ca-chain.cert.pem | 66 - .../certs/client@freeswitch-upstream.cert.pem | 30 - .../controller@freeswitch-downstream.cert.pem | 32 - .../controller@freeswitch-upstream.cert.pem | 31 - .../intermediate/certs/intermediate.cert.pem | 33 - .../master@freeswitch-downstream.cert.pem | 33 - .../cnf/client@freeswitch-upstream.cnf | 133 - .../cnf/controller@freeswitch-upstream.cnf | 133 - .../cnf/master@freeswitch-downstream.cnf | 133 - libs/libblade/test/ca/intermediate/crlnumber | 1 - .../csr/client@freeswitch-upstream.csr.pem | 17 - .../controller@freeswitch-downstream.csr.pem | 17 - .../controller@freeswitch-upstream.csr.pem | 17 - .../ca/intermediate/csr/intermediate.csr.pem | 28 - .../csr/master@freeswitch-downstream.csr.pem | 17 - libs/libblade/test/ca/intermediate/index.txt | 4 - .../test/ca/intermediate/index.txt.attr | 1 - .../test/ca/intermediate/index.txt.attr.old | 1 - .../test/ca/intermediate/index.txt.old | 3 - .../test/ca/intermediate/newcerts/1000.pem | 33 - .../test/ca/intermediate/newcerts/1001.pem | 32 - .../test/ca/intermediate/newcerts/1002.pem | 31 - .../test/ca/intermediate/newcerts/1003.pem | 30 - .../libblade/test/ca/intermediate/openssl.cnf | 132 - .../client@freeswitch-upstream.key.pem | 27 - .../controller@freeswitch-downstream.key.pem | 27 - .../controller@freeswitch-upstream.key.pem | 27 - .../intermediate/private/intermediate.key.pem | 51 - .../master@freeswitch-downstream.key.pem | 27 - libs/libblade/test/ca/intermediate/serial | 1 - libs/libblade/test/ca/intermediate/serial.old | 1 - libs/libblade/test/ca/newcerts/1000.pem | 33 - libs/libblade/test/ca/openssl.cnf | 132 - libs/libblade/test/ca/private/ca.key.pem | 51 - libs/libblade/test/ca/serial | 1 - libs/libblade/test/ca/serial.old | 1 - libs/libblade/test/nodeidgen.c | 16 - libs/libblade/test/tap.c | 354 - libs/libblade/test/tap.h | 115 - libs/libblade/test/testbuckets.c | 1293 - libs/libblade/test/testbuild.c | 23 - libs/libblade/test/testcli.c | 456 - libs/libblade/test/testcli.cfg | 15 - libs/libblade/test/testcli.vcxproj | 217 - libs/libblade/test/testcon.c | 569 - libs/libblade/test/testcon.cfg | 27 - libs/libblade/test/testcon.vcxproj | 217 - libs/libblade/test/testdht2.c | 385 - libs/libks/.gitignore | 10 - libs/libks/AUTHORS | 0 libs/libks/CODING_GUIDELINES | 108 - libs/libks/COPYING | 0 libs/libks/ChangeLog | 0 libs/libks/INSTALL | 370 - libs/libks/Makefile.am | 31 - libs/libks/NEWS | 0 libs/libks/README | 0 libs/libks/acinclude.m4 | 7 - libs/libks/bootstrap.sh | 4 - .../build/config/ac_cflags_gcc_option.m4 | 142 - .../build/config/ac_cflags_sun_option.m4 | 140 - libs/libks/build/config/ac_gcc_archflag.m4 | 148 - libs/libks/build/config/ac_gcc_x86_cpuid.m4 | 21 - libs/libks/build/config/ac_prog_gzip.m4 | 9 - libs/libks/build/config/ac_prog_wget.m4 | 9 - libs/libks/build/config/ax_cc_maxopt.m4 | 120 - .../build/config/ax_cflags_warn_all_ansi.m4 | 94 - .../build/config/ax_check_compiler_flags.m4 | 26 - libs/libks/build/config/ax_compiler_vendor.m4 | 15 - libs/libks/build/config/sac-openssl.m4 | 49 - libs/libks/configure.ac | 256 - libs/libks/crypt/aes.h | 198 - libs/libks/crypt/aes_modes.c | 946 - libs/libks/crypt/aescpp.h | 141 - libs/libks/crypt/aescrypt.c | 294 - libs/libks/crypt/aeskey.c | 556 - libs/libks/crypt/aesopt.h | 742 - libs/libks/crypt/aestab.c | 391 - libs/libks/crypt/aestab.h | 173 - libs/libks/crypt/brg_endian.h | 126 - libs/libks/crypt/brg_types.h | 219 - libs/libks/crypt/sha2.c | 773 - libs/libks/crypt/sha2.h | 151 - libs/libks/crypt/twofish.c | 1750 - libs/libks/crypt/twofish.h | 265 - libs/libks/crypt/twofish_cfb.c | 98 - libs/libks/libks.pc.in | 11 - libs/libks/libks.props | 19 - libs/libks/libks.sln | 168 - libs/libks/libks.vcxproj | 251 - libs/libks/libks.vcxproj.filters | 207 - libs/libks/src/cJSON.c | 2169 - libs/libks/src/cJSON_Utils.c | 881 - libs/libks/src/include/ks.h | 162 - libs/libks/src/include/ks_acl.h | 83 - libs/libks/src/include/ks_base64.h | 54 - libs/libks/src/include/ks_buffer.h | 152 - libs/libks/src/include/ks_cJSON.h | 239 - libs/libks/src/include/ks_cJSON_Utils.h | 44 - libs/libks/src/include/ks_config.h | 170 - libs/libks/src/include/ks_dso.h | 49 - libs/libks/src/include/ks_hash.h | 722 - libs/libks/src/include/ks_json.h | 88 - libs/libks/src/include/ks_platform.h | 297 - libs/libks/src/include/ks_pool.h | 458 - libs/libks/src/include/ks_printf.h | 82 - libs/libks/src/include/ks_q.h | 68 - libs/libks/src/include/ks_rng.h | 56 - libs/libks/src/include/ks_sb.h | 66 - libs/libks/src/include/ks_socket.h | 130 - libs/libks/src/include/ks_ssl.h | 29 - libs/libks/src/include/ks_thread_pool.h | 58 - libs/libks/src/include/ks_threadmutex.h | 161 - libs/libks/src/include/ks_time.h | 65 - libs/libks/src/include/ks_types.h | 252 - libs/libks/src/include/kws.h | 109 - libs/libks/src/include/simclist.h | 1007 - libs/libks/src/ks.c | 201 - libs/libks/src/ks_acl.c | 394 - libs/libks/src/ks_base64.c | 130 - libs/libks/src/ks_buffer.c | 355 - libs/libks/src/ks_config.c | 255 - libs/libks/src/ks_dso.c | 132 - libs/libks/src/ks_hash.c | 695 - libs/libks/src/ks_json.c | 40 - libs/libks/src/ks_log.c | 177 - libs/libks/src/ks_mutex.c | 676 - libs/libks/src/ks_pool.c | 1301 - libs/libks/src/ks_printf.c | 974 - libs/libks/src/ks_q.c | 471 - libs/libks/src/ks_rng.c | 236 - libs/libks/src/ks_sb.c | 227 - libs/libks/src/ks_socket.c | 1055 - libs/libks/src/ks_ssl.c | 258 - libs/libks/src/ks_string.c | 483 - libs/libks/src/ks_thread.c | 324 - libs/libks/src/ks_thread_pool.c | 259 - libs/libks/src/ks_time.c | 270 - libs/libks/src/kws.c | 1263 - libs/libks/src/simclist.c | 1728 - libs/libks/test/.gitignore | 16 - libs/libks/test/Makefile.am | 65 - libs/libks/test/tap.c | 354 - libs/libks/test/tap.h | 115 - libs/libks/test/test_thread_pools.c | 71 - libs/libks/test/test_thread_pools.vcxproj | 194 - libs/libks/test/testacl.c | 70 - libs/libks/test/testacl.vcxproj | 193 - libs/libks/test/testhash.c | 181 - libs/libks/test/testhash.vcxproj | 189 - libs/libks/test/testpolling.c | 115 - libs/libks/test/testpolling.vcxproj | 193 - libs/libks/test/testpools.c | 260 - libs/libks/test/testpools.vcxproj | 190 - libs/libks/test/testq.c | 225 - libs/libks/test/testq.vcxproj | 190 - libs/libks/test/testrealloc.c | 40 - libs/libks/test/testrealloc.vcxproj | 194 - libs/libks/test/testsock.c | 412 - libs/libks/test/testsock.vcxproj | 187 - libs/libks/test/testsock2.c | 20 - libs/libks/test/testthreadmutex.c | 349 - libs/libks/test/testthreadmutex.vcxproj | 187 - libs/libks/test/testtime.c | 45 - libs/libks/test/testtime.vcxproj | 190 - libs/libks/test/testwebsock.c | 287 - libs/libks/test/testwebsock.vcxproj | 194 - libs/win32/Download libconfig.2015.vcxproj | 85 - libs/win32/Download libsodium.2015.vcxproj | 85 - libs/win32/libconfig/libconfig.2015.vcxproj | 350 - .../libconfig/libconfig.2015.vcxproj.filters | 57 - libs/win32/libsodium/libsodium.2015.vcxproj | 564 - .../libsodium/libsodium.2015.vcxproj.filters | 690 - w32/config.props | 18 - w32/sodium.props | 20 - 278 files changed, 130321 deletions(-) delete mode 100644 libs/libblade/.gitignore delete mode 100644 libs/libblade/AUTHORS delete mode 100644 libs/libblade/COPYING delete mode 100644 libs/libblade/ChangeLog delete mode 100644 libs/libblade/INSTALL delete mode 100644 libs/libblade/Makefile.am delete mode 100644 libs/libblade/NEWS delete mode 100644 libs/libblade/README delete mode 100644 libs/libblade/acinclude.m4 delete mode 100755 libs/libblade/bootstrap.sh delete mode 100755 libs/libblade/build/compile delete mode 100644 libs/libblade/build/config/ac_cflags_gcc_option.m4 delete mode 100644 libs/libblade/build/config/ac_cflags_sun_option.m4 delete mode 100644 libs/libblade/build/config/ac_gcc_archflag.m4 delete mode 100644 libs/libblade/build/config/ac_gcc_x86_cpuid.m4 delete mode 100644 libs/libblade/build/config/ac_prog_gzip.m4 delete mode 100644 libs/libblade/build/config/ac_prog_wget.m4 delete mode 100644 libs/libblade/build/config/ax_cc_maxopt.m4 delete mode 100644 libs/libblade/build/config/ax_cflags_warn_all_ansi.m4 delete mode 100644 libs/libblade/build/config/ax_check_compiler_flags.m4 delete mode 100644 libs/libblade/build/config/ax_compiler_vendor.m4 delete mode 100644 libs/libblade/build/config/sac-openssl.m4 delete mode 100644 libs/libblade/configure.ac delete mode 100644 libs/libblade/flows/flow1.json delete mode 100644 libs/libblade/libblade.pc.in delete mode 100644 libs/libblade/libblade.props delete mode 100644 libs/libblade/libblade.sln delete mode 100644 libs/libblade/libblade.vcxproj delete mode 100644 libs/libblade/libblade.vcxproj.filters delete mode 100644 libs/libblade/src/bencode.c delete mode 100644 libs/libblade/src/blade.c delete mode 100644 libs/libblade/src/blade_channel.c delete mode 100644 libs/libblade/src/blade_connection.c delete mode 100644 libs/libblade/src/blade_connectionmgr.c delete mode 100644 libs/libblade/src/blade_identity.c delete mode 100644 libs/libblade/src/blade_mastermgr.c delete mode 100644 libs/libblade/src/blade_protocol.c delete mode 100644 libs/libblade/src/blade_restmgr.c delete mode 100644 libs/libblade/src/blade_routemgr.c delete mode 100644 libs/libblade/src/blade_rpc.c delete mode 100644 libs/libblade/src/blade_rpcmgr.c delete mode 100644 libs/libblade/src/blade_session.c delete mode 100644 libs/libblade/src/blade_sessionmgr.c delete mode 100644 libs/libblade/src/blade_stack.c delete mode 100644 libs/libblade/src/blade_subscription.c delete mode 100644 libs/libblade/src/blade_subscriptionmgr.c delete mode 100644 libs/libblade/src/blade_transport.c delete mode 100644 libs/libblade/src/blade_transport_wss.c delete mode 100644 libs/libblade/src/blade_transportmgr.c delete mode 100644 libs/libblade/src/blade_tuple.c delete mode 100644 libs/libblade/src/blade_web.c delete mode 100644 libs/libblade/src/dht/ks_dht.c delete mode 100644 libs/libblade/src/dht/ks_dht_bucket.c delete mode 100644 libs/libblade/src/dht/ks_dht_datagram.c delete mode 100644 libs/libblade/src/dht/ks_dht_distribute.c delete mode 100644 libs/libblade/src/dht/ks_dht_endpoint.c delete mode 100644 libs/libblade/src/dht/ks_dht_job.c delete mode 100644 libs/libblade/src/dht/ks_dht_message.c delete mode 100644 libs/libblade/src/dht/ks_dht_publish.c delete mode 100644 libs/libblade/src/dht/ks_dht_search.c delete mode 100644 libs/libblade/src/dht/ks_dht_storageitem.c delete mode 100644 libs/libblade/src/dht/ks_dht_transaction.c delete mode 100644 libs/libblade/src/include/blade.h delete mode 100644 libs/libblade/src/include/blade_channel.h delete mode 100644 libs/libblade/src/include/blade_connection.h delete mode 100644 libs/libblade/src/include/blade_connectionmgr.h delete mode 100644 libs/libblade/src/include/blade_identity.h delete mode 100644 libs/libblade/src/include/blade_mastermgr.h delete mode 100644 libs/libblade/src/include/blade_protocol.h delete mode 100644 libs/libblade/src/include/blade_restmgr.h delete mode 100644 libs/libblade/src/include/blade_routemgr.h delete mode 100644 libs/libblade/src/include/blade_rpc.h delete mode 100644 libs/libblade/src/include/blade_rpcmgr.h delete mode 100644 libs/libblade/src/include/blade_session.h delete mode 100644 libs/libblade/src/include/blade_sessionmgr.h delete mode 100644 libs/libblade/src/include/blade_stack.h delete mode 100644 libs/libblade/src/include/blade_subscription.h delete mode 100644 libs/libblade/src/include/blade_subscriptionmgr.h delete mode 100644 libs/libblade/src/include/blade_transport.h delete mode 100644 libs/libblade/src/include/blade_transport_wss.h delete mode 100644 libs/libblade/src/include/blade_transportmgr.h delete mode 100644 libs/libblade/src/include/blade_tuple.h delete mode 100644 libs/libblade/src/include/blade_types.h delete mode 100644 libs/libblade/src/include/blade_web.h delete mode 100644 libs/libblade/src/include/ks_bencode.h delete mode 100644 libs/libblade/src/include/ks_dht-int.h delete mode 100644 libs/libblade/src/include/ks_dht.h delete mode 100644 libs/libblade/src/include/unqlite.h delete mode 100644 libs/libblade/src/ks_bencode.c delete mode 100644 libs/libblade/src/unqlite.c delete mode 100644 libs/libblade/switchblade/Makefile.am delete mode 100644 libs/libblade/switchblade/restroot/test.lp delete mode 100644 libs/libblade/switchblade/switchblade.c delete mode 100644 libs/libblade/switchblade/switchblade.cfg delete mode 100644 libs/libblade/switchblade/switchblade.vcxproj delete mode 100644 libs/libblade/test/.gitignore delete mode 100644 libs/libblade/test/Makefile.am delete mode 100644 libs/libblade/test/ca/certs/ca.cert.pem delete mode 100644 libs/libblade/test/ca/index.txt delete mode 100644 libs/libblade/test/ca/index.txt.attr delete mode 100644 libs/libblade/test/ca/index.txt.old delete mode 100644 libs/libblade/test/ca/intermediate/certs/ca-chain.cert.pem delete mode 100644 libs/libblade/test/ca/intermediate/certs/client@freeswitch-upstream.cert.pem delete mode 100644 libs/libblade/test/ca/intermediate/certs/controller@freeswitch-downstream.cert.pem delete mode 100644 libs/libblade/test/ca/intermediate/certs/controller@freeswitch-upstream.cert.pem delete mode 100644 libs/libblade/test/ca/intermediate/certs/intermediate.cert.pem delete mode 100644 libs/libblade/test/ca/intermediate/certs/master@freeswitch-downstream.cert.pem delete mode 100644 libs/libblade/test/ca/intermediate/cnf/client@freeswitch-upstream.cnf delete mode 100644 libs/libblade/test/ca/intermediate/cnf/controller@freeswitch-upstream.cnf delete mode 100644 libs/libblade/test/ca/intermediate/cnf/master@freeswitch-downstream.cnf delete mode 100644 libs/libblade/test/ca/intermediate/crlnumber delete mode 100644 libs/libblade/test/ca/intermediate/csr/client@freeswitch-upstream.csr.pem delete mode 100644 libs/libblade/test/ca/intermediate/csr/controller@freeswitch-downstream.csr.pem delete mode 100644 libs/libblade/test/ca/intermediate/csr/controller@freeswitch-upstream.csr.pem delete mode 100644 libs/libblade/test/ca/intermediate/csr/intermediate.csr.pem delete mode 100644 libs/libblade/test/ca/intermediate/csr/master@freeswitch-downstream.csr.pem delete mode 100644 libs/libblade/test/ca/intermediate/index.txt delete mode 100644 libs/libblade/test/ca/intermediate/index.txt.attr delete mode 100644 libs/libblade/test/ca/intermediate/index.txt.attr.old delete mode 100644 libs/libblade/test/ca/intermediate/index.txt.old delete mode 100644 libs/libblade/test/ca/intermediate/newcerts/1000.pem delete mode 100644 libs/libblade/test/ca/intermediate/newcerts/1001.pem delete mode 100644 libs/libblade/test/ca/intermediate/newcerts/1002.pem delete mode 100644 libs/libblade/test/ca/intermediate/newcerts/1003.pem delete mode 100644 libs/libblade/test/ca/intermediate/openssl.cnf delete mode 100644 libs/libblade/test/ca/intermediate/private/client@freeswitch-upstream.key.pem delete mode 100644 libs/libblade/test/ca/intermediate/private/controller@freeswitch-downstream.key.pem delete mode 100644 libs/libblade/test/ca/intermediate/private/controller@freeswitch-upstream.key.pem delete mode 100644 libs/libblade/test/ca/intermediate/private/intermediate.key.pem delete mode 100644 libs/libblade/test/ca/intermediate/private/master@freeswitch-downstream.key.pem delete mode 100644 libs/libblade/test/ca/intermediate/serial delete mode 100644 libs/libblade/test/ca/intermediate/serial.old delete mode 100644 libs/libblade/test/ca/newcerts/1000.pem delete mode 100644 libs/libblade/test/ca/openssl.cnf delete mode 100644 libs/libblade/test/ca/private/ca.key.pem delete mode 100644 libs/libblade/test/ca/serial delete mode 100644 libs/libblade/test/ca/serial.old delete mode 100644 libs/libblade/test/nodeidgen.c delete mode 100644 libs/libblade/test/tap.c delete mode 100644 libs/libblade/test/tap.h delete mode 100644 libs/libblade/test/testbuckets.c delete mode 100644 libs/libblade/test/testbuild.c delete mode 100644 libs/libblade/test/testcli.c delete mode 100644 libs/libblade/test/testcli.cfg delete mode 100644 libs/libblade/test/testcli.vcxproj delete mode 100644 libs/libblade/test/testcon.c delete mode 100644 libs/libblade/test/testcon.cfg delete mode 100644 libs/libblade/test/testcon.vcxproj delete mode 100644 libs/libblade/test/testdht2.c delete mode 100644 libs/libks/.gitignore delete mode 100644 libs/libks/AUTHORS delete mode 100644 libs/libks/CODING_GUIDELINES delete mode 100644 libs/libks/COPYING delete mode 100644 libs/libks/ChangeLog delete mode 100644 libs/libks/INSTALL delete mode 100644 libs/libks/Makefile.am delete mode 100644 libs/libks/NEWS delete mode 100644 libs/libks/README delete mode 100644 libs/libks/acinclude.m4 delete mode 100755 libs/libks/bootstrap.sh delete mode 100644 libs/libks/build/config/ac_cflags_gcc_option.m4 delete mode 100644 libs/libks/build/config/ac_cflags_sun_option.m4 delete mode 100644 libs/libks/build/config/ac_gcc_archflag.m4 delete mode 100644 libs/libks/build/config/ac_gcc_x86_cpuid.m4 delete mode 100644 libs/libks/build/config/ac_prog_gzip.m4 delete mode 100644 libs/libks/build/config/ac_prog_wget.m4 delete mode 100644 libs/libks/build/config/ax_cc_maxopt.m4 delete mode 100644 libs/libks/build/config/ax_cflags_warn_all_ansi.m4 delete mode 100644 libs/libks/build/config/ax_check_compiler_flags.m4 delete mode 100644 libs/libks/build/config/ax_compiler_vendor.m4 delete mode 100644 libs/libks/build/config/sac-openssl.m4 delete mode 100644 libs/libks/configure.ac delete mode 100644 libs/libks/crypt/aes.h delete mode 100644 libs/libks/crypt/aes_modes.c delete mode 100644 libs/libks/crypt/aescpp.h delete mode 100644 libs/libks/crypt/aescrypt.c delete mode 100644 libs/libks/crypt/aeskey.c delete mode 100644 libs/libks/crypt/aesopt.h delete mode 100644 libs/libks/crypt/aestab.c delete mode 100644 libs/libks/crypt/aestab.h delete mode 100644 libs/libks/crypt/brg_endian.h delete mode 100644 libs/libks/crypt/brg_types.h delete mode 100644 libs/libks/crypt/sha2.c delete mode 100644 libs/libks/crypt/sha2.h delete mode 100644 libs/libks/crypt/twofish.c delete mode 100755 libs/libks/crypt/twofish.h delete mode 100755 libs/libks/crypt/twofish_cfb.c delete mode 100644 libs/libks/libks.pc.in delete mode 100644 libs/libks/libks.props delete mode 100644 libs/libks/libks.sln delete mode 100644 libs/libks/libks.vcxproj delete mode 100644 libs/libks/libks.vcxproj.filters delete mode 100644 libs/libks/src/cJSON.c delete mode 100644 libs/libks/src/cJSON_Utils.c delete mode 100644 libs/libks/src/include/ks.h delete mode 100644 libs/libks/src/include/ks_acl.h delete mode 100644 libs/libks/src/include/ks_base64.h delete mode 100644 libs/libks/src/include/ks_buffer.h delete mode 100644 libs/libks/src/include/ks_cJSON.h delete mode 100644 libs/libks/src/include/ks_cJSON_Utils.h delete mode 100644 libs/libks/src/include/ks_config.h delete mode 100755 libs/libks/src/include/ks_dso.h delete mode 100644 libs/libks/src/include/ks_hash.h delete mode 100644 libs/libks/src/include/ks_json.h delete mode 100644 libs/libks/src/include/ks_platform.h delete mode 100644 libs/libks/src/include/ks_pool.h delete mode 100644 libs/libks/src/include/ks_printf.h delete mode 100644 libs/libks/src/include/ks_q.h delete mode 100644 libs/libks/src/include/ks_rng.h delete mode 100644 libs/libks/src/include/ks_sb.h delete mode 100644 libs/libks/src/include/ks_socket.h delete mode 100644 libs/libks/src/include/ks_ssl.h delete mode 100644 libs/libks/src/include/ks_thread_pool.h delete mode 100644 libs/libks/src/include/ks_threadmutex.h delete mode 100644 libs/libks/src/include/ks_time.h delete mode 100644 libs/libks/src/include/ks_types.h delete mode 100644 libs/libks/src/include/kws.h delete mode 100755 libs/libks/src/include/simclist.h delete mode 100644 libs/libks/src/ks.c delete mode 100644 libs/libks/src/ks_acl.c delete mode 100644 libs/libks/src/ks_base64.c delete mode 100644 libs/libks/src/ks_buffer.c delete mode 100644 libs/libks/src/ks_config.c delete mode 100755 libs/libks/src/ks_dso.c delete mode 100644 libs/libks/src/ks_hash.c delete mode 100644 libs/libks/src/ks_json.c delete mode 100644 libs/libks/src/ks_log.c delete mode 100644 libs/libks/src/ks_mutex.c delete mode 100644 libs/libks/src/ks_pool.c delete mode 100644 libs/libks/src/ks_printf.c delete mode 100644 libs/libks/src/ks_q.c delete mode 100644 libs/libks/src/ks_rng.c delete mode 100644 libs/libks/src/ks_sb.c delete mode 100644 libs/libks/src/ks_socket.c delete mode 100644 libs/libks/src/ks_ssl.c delete mode 100644 libs/libks/src/ks_string.c delete mode 100644 libs/libks/src/ks_thread.c delete mode 100644 libs/libks/src/ks_thread_pool.c delete mode 100644 libs/libks/src/ks_time.c delete mode 100644 libs/libks/src/kws.c delete mode 100755 libs/libks/src/simclist.c delete mode 100644 libs/libks/test/.gitignore delete mode 100644 libs/libks/test/Makefile.am delete mode 100644 libs/libks/test/tap.c delete mode 100644 libs/libks/test/tap.h delete mode 100644 libs/libks/test/test_thread_pools.c delete mode 100644 libs/libks/test/test_thread_pools.vcxproj delete mode 100644 libs/libks/test/testacl.c delete mode 100644 libs/libks/test/testacl.vcxproj delete mode 100644 libs/libks/test/testhash.c delete mode 100644 libs/libks/test/testhash.vcxproj delete mode 100644 libs/libks/test/testpolling.c delete mode 100644 libs/libks/test/testpolling.vcxproj delete mode 100644 libs/libks/test/testpools.c delete mode 100644 libs/libks/test/testpools.vcxproj delete mode 100644 libs/libks/test/testq.c delete mode 100644 libs/libks/test/testq.vcxproj delete mode 100644 libs/libks/test/testrealloc.c delete mode 100644 libs/libks/test/testrealloc.vcxproj delete mode 100644 libs/libks/test/testsock.c delete mode 100644 libs/libks/test/testsock.vcxproj delete mode 100644 libs/libks/test/testsock2.c delete mode 100644 libs/libks/test/testthreadmutex.c delete mode 100644 libs/libks/test/testthreadmutex.vcxproj delete mode 100644 libs/libks/test/testtime.c delete mode 100644 libs/libks/test/testtime.vcxproj delete mode 100644 libs/libks/test/testwebsock.c delete mode 100644 libs/libks/test/testwebsock.vcxproj delete mode 100644 libs/win32/Download libconfig.2015.vcxproj delete mode 100644 libs/win32/Download libsodium.2015.vcxproj delete mode 100644 libs/win32/libconfig/libconfig.2015.vcxproj delete mode 100644 libs/win32/libconfig/libconfig.2015.vcxproj.filters delete mode 100644 libs/win32/libsodium/libsodium.2015.vcxproj delete mode 100644 libs/win32/libsodium/libsodium.2015.vcxproj.filters delete mode 100644 w32/config.props delete mode 100644 w32/sodium.props diff --git a/.gitignore b/.gitignore index 8cafb4cff8..ff9c25c0e2 100644 --- a/.gitignore +++ b/.gitignore @@ -255,17 +255,3 @@ libs/broadvoice-*/ libs/libcodec2-*/ libs/libsilk-*/ -libs/libconfig-* -libs/libsodium-* -libs/civetweb-* -libs/libblade/libblade.VC.db -libs/libblade/libblade.VC.VC.opendb -libs/libblade/Win32/ -libs/libblade/x64/ -libs/libks/libks.VC.db -libs/libks/libks.VC.VC.opendb -libs/pax_global_header -libs/win32/libconfig/Win32 -libs/win32/libconfig/x64 -libs/win32/libsodium/Win32 -libs/win32/libsodium/x64 diff --git a/debian/copyright b/debian/copyright index 915ab87830..eba56ce503 100644 --- a/debian/copyright +++ b/debian/copyright @@ -1693,24 +1693,6 @@ Files: src/switch_dso.c Copyright: 2008 Michael Jerris License: BSD-like -Files: libs/libks/* - libs/libscgi/src/include/scgi_oop.h - libs/libscgi/src/scgi.c -Copyright: 2007-2013, Anthony Minessale II - 2007 Michael Jerris - 1996-2000 Gray Watson -License: BSD-3-clause - -Files: libs/libks/*/ks_json.[ch] - src/include/switch_json.h - src/switch_json.c -Copyright: 2009 Dave Gamble -License: MIT/X11 (BSD like) - -Files: libs/libks/*/simclist.[ch] -Copyright: 2007-2011 Mij -License: ISC - Files: libs/libtpl-1.5/src/tpl.[ch] Copyright: 2005-2010, Troy D. Hanson License: BSD-2-clause diff --git a/libs/libblade/.gitignore b/libs/libblade/.gitignore deleted file mode 100644 index c58d005878..0000000000 --- a/libs/libblade/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -Makefile -Makefile.in -build/*.m4 -configure diff --git a/libs/libblade/AUTHORS b/libs/libblade/AUTHORS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libblade/COPYING b/libs/libblade/COPYING deleted file mode 100644 index 8b13789179..0000000000 --- a/libs/libblade/COPYING +++ /dev/null @@ -1 +0,0 @@ - diff --git a/libs/libblade/ChangeLog b/libs/libblade/ChangeLog deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libblade/INSTALL b/libs/libblade/INSTALL deleted file mode 100644 index 2099840756..0000000000 --- a/libs/libblade/INSTALL +++ /dev/null @@ -1,370 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994-1996, 1999-2002, 2004-2013 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 command `./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 `' 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 limitation. Until the limitation is lifted, you can use -this workaround: - - CONFIG_SHELL=/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/libs/libblade/Makefile.am b/libs/libblade/Makefile.am deleted file mode 100644 index 56484ff912..0000000000 --- a/libs/libblade/Makefile.am +++ /dev/null @@ -1,57 +0,0 @@ -ACLOCAL_AMFLAGS=-I build -EXTRA_DIST = -SUBDIRS = . test switchblade -AUTOMAKE_OPTIONS = subdir-objects - -CIVETWEB_VERSION=1.9.1 -CIVETWEB=civetweb-$(CIVETWEB_VERSION) -CIVETWEB_DIR=$(top_srcdir)/../$(CIVETWEB) -CIVETWEB_LIB=$(top_srcdir)/../$(CIVETWEB)/libcivetweb.a -LIBKS_DIR=$(top_srcdir)/../libks -LIBKS=$(LIBKS_DIR)/libks.la - -AM_CFLAGS += -I$(top_srcdir)/src -I$(top_srcdir)/src/include -I$(CIVETWEB_DIR)/include -I$(LIBKS_DIR)/src/include -AM_LDFLAGS += -L$(CIVETWEB_DIR) - -noinst_LTLIBRARIES = libunqlite.la -libunqlite_la_SOURCES = src/unqlite.c -libunqlite_la_CFLAGS = -DUNQLITE_ENABLE_THREADS -libunqlite_la_LIBADD = -lpthread - -lib_LTLIBRARIES = libblade.la -libblade_la_SOURCES = src/blade.c src/blade_stack.c -libblade_la_SOURCES += src/blade_transportmgr.c src/blade_rpcmgr.c src/blade_routemgr.c src/blade_subscriptionmgr.c -libblade_la_SOURCES += src/blade_mastermgr.c src/blade_connectionmgr.c src/blade_sessionmgr.c src/blade_restmgr.c -libblade_la_SOURCES += src/blade_identity.c src/blade_rpc.c src/blade_connection.c src/blade_session.c -libblade_la_SOURCES += src/blade_protocol.c src/blade_subscription.c src/blade_channel.c -libblade_la_SOURCES += src/blade_transport.c src/blade_transport_wss.c src/blade_web.c - -libblade_la_CFLAGS = $(AM_CFLAGS) $(AM_CPPFLAGS) $(PCRE_CFLAGS) -libblade_la_LDFLAGS = -version-info 0:1:0 -lncurses -lpthread -lm -lconfig -lcivetweb $(AM_LDFLAGS) -libblade_la_LIBADD = libunqlite.la $(PCRE_LIBS) - -library_includedir = $(prefix)/include -library_include_HEADERS = src/include/blade.h src/include/blade_types.h src/include/blade_stack.h -library_include_HEADERS += src/include/blade_transportmgr.h src/include/blade_rpcmgr.h src/include/blade_routemgr.h src/include/blade_subscriptionmgr.h -library_include_HEADERS += src/include/blade_mastermgr.h src/include/blade_connectionmgr.h src/include/blade_sessionmgr.h src/include/blade_restmgr.h -library_include_HEADERS += src/include/blade_identity.h src/include/blade_rpc.h src/include/blade_connection.h src/include/blade_session.h -library_include_HEADERS += src/include/blade_protocol.h src/include/blade_subscription.h src/include/blade_channel.h -library_include_HEADERS += src/include/blade_transport.h src/include/blade_transport_wss.h src/include/blade_web.h -library_include_HEADERS += src/include/unqlite.h test/tap.h - -BUILT_SOURCES=$(CIVETWEB_LIB) $(LIBKS) - -$(CIVETWEB_LIB): $(CIVETWEB_DIR) - cd $(CIVETWEB_DIR) && $(MAKE) lib USE_STACK_SIZE=102400 MAX_REQUEST_SIZE=16384 WITH_LUA=1 LUA_COMPAT_ALL=1 USE_LUA_SQLITE3=1 USE_LUA_FILE_SYSTEM=1 WITH_IPV6=1 WITH_WEBSOCKET=1 && $(MAKE) lib USE_STACK_SIZE=102400 MAX_REQUEST_SIZE=16384 WITH_LUA=1 LUA_COMPAT_ALL=1 USE_LUA_SQLITE3=1 USE_LUA_FILE_SYSTEM=1 WITH_IPV6=1 WITH_WEBSOCKET=1 WITH_DUKTAPE=1 - -$(CIVETWEB_DIR): - $(GETLIB) $(CIVETWEB).tar.gz - -$(LIBKS): - cd $(top_srcdir)/../libks && /bin/sh ./bootstrap.sh && /bin/sh ./configure && $(MAKE) - -tests: libblade.la - $(MAKE) -C test tests - -switchblade: libblade.la - $(MAKE) -C switchblade sb diff --git a/libs/libblade/NEWS b/libs/libblade/NEWS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libblade/README b/libs/libblade/README deleted file mode 100644 index f298201392..0000000000 --- a/libs/libblade/README +++ /dev/null @@ -1,26 +0,0 @@ - -== Build == -To build against the in tree version of libks follow these steps, from the starting point of ./libs/libblade/: - - -cd ../libks/ -./bootstrap.sh -./configure -make -make check - -cd ../libblade/ -./boostrap.sh -./configure --with-libks=`realpath ../libks/` -make -make check - - - -If you are trying to run the 'make distcheck' target while using the -in tree version of libks, then you need to specify the -DISTCHECK_CONFIGURE_FLAGS env variable like: - - -DISTCHECK_CONFIGURE_FLAGS="--with-libks=/usr/src/freeswitch/libs/libks" make distcheck - diff --git a/libs/libblade/acinclude.m4 b/libs/libblade/acinclude.m4 deleted file mode 100644 index 1b464ca796..0000000000 --- a/libs/libblade/acinclude.m4 +++ /dev/null @@ -1,7 +0,0 @@ -m4_include([build/config/ax_compiler_vendor.m4]) -m4_include([build/config/ax_cflags_warn_all_ansi.m4]) -m4_include([build/config/ax_cc_maxopt.m4]) -m4_include([build/config/ax_check_compiler_flags.m4]) -m4_include([build/config/ac_gcc_archflag.m4]) -m4_include([build/config/ac_gcc_x86_cpuid.m4]) -m4_include([build/config/sac-openssl.m4]) diff --git a/libs/libblade/bootstrap.sh b/libs/libblade/bootstrap.sh deleted file mode 100755 index e8ca45f592..0000000000 --- a/libs/libblade/bootstrap.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -set -x -${AUTORECONF:-autoreconf} -fi diff --git a/libs/libblade/build/compile b/libs/libblade/build/compile deleted file mode 100755 index 531136b068..0000000000 --- a/libs/libblade/build/compile +++ /dev/null @@ -1,347 +0,0 @@ -#! /bin/sh -# Wrapper for compilers which do not understand '-c -o'. - -scriptversion=2012-10-14.11; # UTC - -# Copyright (C) 1999-2013 Free Software Foundation, Inc. -# Written by Tom Tromey . -# -# 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 . - -# 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 or send patches to -# . - -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*) - 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/*) - 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 . -EOF - exit $? - ;; - -v | --v*) - echo "compile $scriptversion" - exit $? - ;; - cl | *[/\\]cl | cl.exe | *[/\\]cl.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 '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/libs/libblade/build/config/ac_cflags_gcc_option.m4 b/libs/libblade/build/config/ac_cflags_gcc_option.m4 deleted file mode 100644 index e651a5e6c5..0000000000 --- a/libs/libblade/build/config/ac_cflags_gcc_option.m4 +++ /dev/null @@ -1,142 +0,0 @@ -AC_DEFUN([AX_CFLAGS_GCC_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($2,$2,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($2,$2,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl ------------------------------------------------------------------------- - -AC_DEFUN([AX_CFLAGS_GCC_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($1,$1,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($1,$1,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -AC_DEFUN([AX_CFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, -[AX_CFLAGS_GCC_OPTION_NEW($@)],[AX_CFLAGS_GCC_OPTION_OLD($@)])]) - -AC_DEFUN([AX_CXXFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, -[AX_CXXFLAGS_GCC_OPTION_NEW($@)],[AX_CXXFLAGS_GCC_OPTION_OLD($@)])]) - diff --git a/libs/libblade/build/config/ac_cflags_sun_option.m4 b/libs/libblade/build/config/ac_cflags_sun_option.m4 deleted file mode 100644 index a09e6fb695..0000000000 --- a/libs/libblade/build/config/ac_cflags_sun_option.m4 +++ /dev/null @@ -1,140 +0,0 @@ -AC_DEFUN([AX_CFLAGS_SUN_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_sun_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for sun/cc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($2,$2,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_SUN_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_sun_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for sun/cc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($2,$2,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl ----------------------------------------------------------------------- - -AC_DEFUN([AX_CFLAGS_SUN_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_sun_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for sun/cc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($1,$1,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_SUN_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_sun_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for sun/cc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($1,$1,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -AC_DEFUN([AX_CFLAGS_SUN_OPTION],[ifelse(m4_regexp([$2],[-]),-1, -[AX_CFLAGS_SUN_OPTION_NEW($@)],[AX_CFLAGS_SUN_OPTION_OLD($@)])]) - -AC_DEFUN([AX_CXXFLAGS_SUN_OPTION],[ifelse(m4_regexp([$2],[-]),-1, -[AX_CXXFLAGS_SUN_OPTION_NEW($@)],[AX_CXXFLAGS_SUN_OPTION_OLD($@)])]) - diff --git a/libs/libblade/build/config/ac_gcc_archflag.m4 b/libs/libblade/build/config/ac_gcc_archflag.m4 deleted file mode 100644 index b38a564902..0000000000 --- a/libs/libblade/build/config/ac_gcc_archflag.m4 +++ /dev/null @@ -1,148 +0,0 @@ -AC_DEFUN([AX_GCC_ARCHFLAG], -[AC_REQUIRE([AC_PROG_CC]) - -AC_ARG_WITH(gcc-arch, [AC_HELP_STRING([--with-gcc-arch=], [use architecture for gcc -march/-mtune, instead of guessing])], - ax_gcc_arch=$withval, ax_gcc_arch=yes) - -AC_MSG_CHECKING([for gcc architecture flag]) -AC_MSG_RESULT([]) -AC_CACHE_VAL(ax_cv_gcc_archflag, -[ -ax_cv_gcc_archflag="unknown" - -if test "$GCC" = yes; then - -if test "x$ax_gcc_arch" = xyes; then -ax_gcc_arch="" -if test "$cross_compiling" = no; then -case $host_cpu in - i[[3456]]86*|x86_64*) # use cpuid codes, in part from x86info-1.7 by D. Jones - AX_GCC_X86_CPUID(0) - AX_GCC_X86_CPUID(1) - case $ax_cv_gcc_x86_cpuid_0 in - *:756e6547:*:*) # Intel - case $ax_cv_gcc_x86_cpuid_1 in - *5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;; - *5??:*:*:*) ax_gcc_arch=pentium ;; - *6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; - *6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; - *6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; - *6[[9d]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;; - *6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; - *6??:*:*:*) ax_gcc_arch=pentiumpro ;; - *f3[[347]]:*:*:*|*f4[1347]:*:*:*) - case $host_cpu in - x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;; - *) ax_gcc_arch="prescott pentium4 pentiumpro" ;; - esac ;; - *f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";; - esac ;; - *:68747541:*:*) # AMD - case $ax_cv_gcc_x86_cpuid_1 in - *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;; - *5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;; - *5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;; - *60?:*:*:*) ax_gcc_arch=k7 ;; - *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;; - *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;; - *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;; - *6[[68a]]?:*:*:*) - AX_GCC_X86_CPUID(0x80000006) # L2 cache size - case $ax_cv_gcc_x86_cpuid_0x80000006 in - *:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256 - ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;; - *) ax_gcc_arch="athlon-4 athlon k7" ;; - esac ;; - *f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;; - *f5?:*:*:*) ax_gcc_arch="opteron k8" ;; - *f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;; - *f??:*:*:*) ax_gcc_arch="k8" ;; - esac ;; - *:746e6543:*:*) # IDT - case $ax_cv_gcc_x86_cpuid_1 in - *54?:*:*:*) ax_gcc_arch=winchip-c6 ;; - *58?:*:*:*) ax_gcc_arch=winchip2 ;; - *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;; - *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;; - esac ;; - esac - if test x"$ax_gcc_arch" = x; then # fallback - case $host_cpu in - i586*) ax_gcc_arch=pentium ;; - i686*) ax_gcc_arch=pentiumpro ;; - esac - fi - ;; - - sparc*) - AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/]) - cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null` - cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters` - case $cputype in - *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;; - *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;; - *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;; - *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;; - *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;; - *cypress*) ax_gcc_arch=cypress ;; - esac ;; - - alphaev5) ax_gcc_arch=ev5 ;; - alphaev56) ax_gcc_arch=ev56 ;; - alphapca56) ax_gcc_arch="pca56 ev56" ;; - alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;; - alphaev6) ax_gcc_arch=ev6 ;; - alphaev67) ax_gcc_arch=ev67 ;; - alphaev68) ax_gcc_arch="ev68 ev67" ;; - alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;; - alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;; - alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;; - - powerpc*) - cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null` - cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'` - case $cputype in - *750*) ax_gcc_arch="750 G3" ;; - *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;; - *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;; - *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;; - *970*) ax_gcc_arch="970 G5 power4";; - *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; - *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; - 603ev|8240) ax_gcc_arch="$cputype 603e 603";; - *) ax_gcc_arch=$cputype ;; - esac - ax_gcc_arch="$ax_gcc_arch powerpc" - ;; -esac -fi # not cross-compiling -fi # guess arch - -if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then -for arch in $ax_gcc_arch; do - if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code - flags="-mtune=$arch" - # -mcpu=$arch and m$arch generate nonportable code on every arch except - # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr. - case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac - else - flags="-march=$arch -mcpu=$arch -m$arch" - fi - for flag in $flags; do - AX_CHECK_COMPILER_FLAGS($flag, [ax_cv_gcc_archflag=$flag; break]) - done - test "x$ax_cv_gcc_archflag" = xunknown || break -done -fi - -fi # $GCC=yes -]) -AC_MSG_CHECKING([for gcc architecture flag]) -AC_MSG_RESULT($ax_cv_gcc_archflag) -if test "x$ax_cv_gcc_archflag" = xunknown; then - m4_default([$3],:) -else - m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"]) -fi -]) - diff --git a/libs/libblade/build/config/ac_gcc_x86_cpuid.m4 b/libs/libblade/build/config/ac_gcc_x86_cpuid.m4 deleted file mode 100644 index 3cf22d0dde..0000000000 --- a/libs/libblade/build/config/ac_gcc_x86_cpuid.m4 +++ /dev/null @@ -1,21 +0,0 @@ -AC_DEFUN([AX_GCC_X86_CPUID], -[AC_REQUIRE([AC_PROG_CC]) -AC_LANG_PUSH([C]) -AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1, - [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ - int op = $1, eax, ebx, ecx, edx; - FILE *f; - __asm__("cpuid" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "a" (op)); - f = fopen("conftest_cpuid", "w"); if (!f) return 1; - fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); - fclose(f); - return 0; -])], - [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], - [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], - [ax_cv_gcc_x86_cpuid_$1=unknown])]) -AC_LANG_POP([C]) -]) - diff --git a/libs/libblade/build/config/ac_prog_gzip.m4 b/libs/libblade/build/config/ac_prog_gzip.m4 deleted file mode 100644 index f37a4cc9ce..0000000000 --- a/libs/libblade/build/config/ac_prog_gzip.m4 +++ /dev/null @@ -1,9 +0,0 @@ -AC_DEFUN([AC_PROG_GZIP],[ -AC_CHECK_PROGS(gzip,[gzip],no) -export gzip; -if test $gzip = "no" ; -then - AC_MSG_ERROR([Unable to find the gzip application]); -fi -AC_SUBST(gzip) -]) diff --git a/libs/libblade/build/config/ac_prog_wget.m4 b/libs/libblade/build/config/ac_prog_wget.m4 deleted file mode 100644 index 56b6b8334f..0000000000 --- a/libs/libblade/build/config/ac_prog_wget.m4 +++ /dev/null @@ -1,9 +0,0 @@ -AC_DEFUN([AC_PROG_WGET],[ -AC_CHECK_PROGS(wget,[wget],no) -export wget; -if test $wget = "no" ; -then - AC_MSG_ERROR([Unable to find the wget application]); -fi -AC_SUBST(wget) -]) diff --git a/libs/libblade/build/config/ax_cc_maxopt.m4 b/libs/libblade/build/config/ax_cc_maxopt.m4 deleted file mode 100644 index 6205ee84c8..0000000000 --- a/libs/libblade/build/config/ax_cc_maxopt.m4 +++ /dev/null @@ -1,120 +0,0 @@ -AC_DEFUN([AX_CC_MAXOPT], -[ -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AX_COMPILER_VENDOR]) - -AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disable compiler optimizations that would produce unportable binaries])], - acx_maxopt_portable=$withval, acx_maxopt_portable=no) - -# Try to determine "good" native compiler flags if none specified via CFLAGS -if test "$ac_test_CFLAGS" != "set"; then - CFLAGS="" - case $ax_cv_c_compiler_vendor in - dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" - if test "x$acx_maxopt_portable" = xno; then - CFLAGS="$CFLAGS -arch host" - fi;; - - sun) CFLAGS="-native -fast -xO5 -dalign -xc99=all" - if test "x$acx_maxopt_portable" = xyes; then - CFLAGS="$CFLAGS -xarch=generic" - fi;; - - hp) CFLAGS="+Oall +Optrs_ansi +DSnative" - if test "x$acx_maxopt_portable" = xyes; then - CFLAGS="$CFLAGS +DAportable" - fi;; - - ibm) if test "x$acx_maxopt_portable" = xno; then - xlc_opt="-qarch=auto -qtune=auto" - else - xlc_opt="-qtune=auto" - fi - AX_CHECK_COMPILER_FLAGS($xlc_opt, - CFLAGS="-O3 -qansialias -w $xlc_opt", - [CFLAGS="-O3 -qansialias -w" - echo "******************************************************" - echo "* You seem to have the IBM C compiler. It is *" - echo "* recommended for best performance that you use: *" - echo "* *" - echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" - echo "* ^^^ ^^^ *" - echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" - echo "* CPU you have. (Set the CFLAGS environment var. *" - echo "* and re-run configure.) For more info, man cc. *" - echo "******************************************************"]) - ;; - - intel) CFLAGS="-O3 -ansi_alias" - if test "x$acx_maxopt_portable" = xno; then - icc_archflag=unknown - icc_flags="" - case $host_cpu in - i686*|x86_64*) - # icc accepts gcc assembly syntax, so these should work: - AX_GCC_X86_CPUID(0) - AX_GCC_X86_CPUID(1) - case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG - *:756e6547:*:*) # Intel - case $ax_cv_gcc_x86_cpuid_1 in - *6a?:*[[234]]:*:*|*6[[789b]]?:*:*:*) icc_flags="-xK";; - *f3[[347]]:*:*:*|*f4[1347]:*:*:*) icc_flags="-xP -xN -xW -xK";; - *f??:*:*:*) icc_flags="-xN -xW -xK";; - esac ;; - esac ;; - esac - if test "x$icc_flags" != x; then - for flag in $icc_flags; do - AX_CHECK_COMPILER_FLAGS($flag, [icc_archflag=$flag; break]) - done - fi - AC_MSG_CHECKING([for icc architecture flag]) - AC_MSG_RESULT($icc_archflag) - if test "x$icc_archflag" != xunknown; then - CFLAGS="$CFLAGS $icc_archflag" - fi - fi - ;; - - gnu) - # default optimization flags for gcc on all systems - CFLAGS="-O3 -fomit-frame-pointer" - - # -malign-double for x86 systems - AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double") - - # -fstrict-aliasing for gcc-2.95+ - AX_CHECK_COMPILER_FLAGS(-fstrict-aliasing, - CFLAGS="$CFLAGS -fstrict-aliasing") - - # note that we enable "unsafe" fp optimization with other compilers, too - AX_CHECK_COMPILER_FLAGS(-ffast-math, CFLAGS="$CFLAGS -ffast-math") - - AX_GCC_ARCHFLAG($acx_maxopt_portable) - ;; - esac - - if test -z "$CFLAGS"; then - echo "" - echo "********************************************************" - echo "* WARNING: Don't know the best CFLAGS for this system *" - echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" - echo "********************************************************" - echo "" - CFLAGS="-O3" - fi - - AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [ - echo "" - echo "********************************************************" - echo "* WARNING: The guessed CFLAGS don't seem to work with *" - echo "* your compiler. *" - echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "********************************************************" - echo "" - CFLAGS="" - ]) - -fi -]) diff --git a/libs/libblade/build/config/ax_cflags_warn_all_ansi.m4 b/libs/libblade/build/config/ax_cflags_warn_all_ansi.m4 deleted file mode 100644 index da950f439b..0000000000 --- a/libs/libblade/build/config/ax_cflags_warn_all_ansi.m4 +++ /dev/null @@ -1,94 +0,0 @@ -AC_DEFUN([AX_CFLAGS_WARN_ALL_ANSI],[dnl -AS_VAR_PUSHDEF([FLAGS],[AM_CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all_ansi])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -# IRIX C compiler: -# -use_readonly_const is the default for IRIX C, -# puts them into .rodata, but they are copied later. -# need to be "-G0 -rdatashared" for strictmode but -# I am not sure what effect that has really. - guidod -for ac_arg dnl -in "-pedantic % -Wall -std=c99 -pedantic" dnl GCC - "-xstrconst % -v -xc99=all" dnl Solaris C - "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix - " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX - " % -ansi -ansiE -fullwarn" dnl IRIX - "+ESlit % +w1 -Aa" dnl HP-UX C - "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) - "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ - AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_WARN_ALL_ANSI],[dnl -AS_VAR_PUSHDEF([FLAGS],[AM_CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all_ansi])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -# IRIX C compiler: -# -use_readonly_const is the default for IRIX C, -# puts them into .rodata, but they are copied later. -# need to be "-G0 -rdatashared" for strictmode but -# I am not sure what effect that has really. - guidod -for ac_arg dnl -in "-pedantic % -Wall -ansi -pedantic" dnl GCC - "-xstrconst % -v -Xc" dnl Solaris C - "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix - " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX - " % -ansi -ansiE -fullwarn" dnl IRIX - "+ESlit % +w1 -Aa" dnl HP-UX C - "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) - "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ - AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - diff --git a/libs/libblade/build/config/ax_check_compiler_flags.m4 b/libs/libblade/build/config/ax_check_compiler_flags.m4 deleted file mode 100644 index 73377b7c59..0000000000 --- a/libs/libblade/build/config/ax_check_compiler_flags.m4 +++ /dev/null @@ -1,26 +0,0 @@ -AC_DEFUN([AX_CHECK_COMPILER_FLAGS], -[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX -AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1]) -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: -AS_LITERAL_IF([$1], - [AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1), [ - ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS - _AC_LANG_PREFIX[]FLAGS="$1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], - AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes, - AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no) - _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])], - [ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS - _AC_LANG_PREFIX[]FLAGS="$1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], - eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes, - eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no) - _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS]) -eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1) -AC_MSG_RESULT($ax_check_compiler_flags) -if test "x$ax_check_compiler_flags" = xyes; then - m4_default([$2], :) -else - m4_default([$3], :) -fi -])dnl AX_CHECK_COMPILER_FLAG diff --git a/libs/libblade/build/config/ax_compiler_vendor.m4 b/libs/libblade/build/config/ax_compiler_vendor.m4 deleted file mode 100644 index a24a58da0f..0000000000 --- a/libs/libblade/build/config/ax_compiler_vendor.m4 +++ /dev/null @@ -1,15 +0,0 @@ -AC_DEFUN([AX_COMPILER_VENDOR], -[ -AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, - [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown - # note: don't check for gcc first since some other compilers define __GNUC__ - for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do - vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ -#if !($vencpp) - thisisanerror; -#endif -])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break]) - done - ]) -]) diff --git a/libs/libblade/build/config/sac-openssl.m4 b/libs/libblade/build/config/sac-openssl.m4 deleted file mode 100644 index 289d3e132e..0000000000 --- a/libs/libblade/build/config/sac-openssl.m4 +++ /dev/null @@ -1,49 +0,0 @@ -dnl ====================================================================== -dnl SAC_OPENSSL -dnl ====================================================================== -AC_DEFUN([SAC_OPENSSL], [ - -AC_ARG_WITH(openssl, -[ --with-openssl use OpenSSL [[enabled]]],, with_openssl=pkg-config) - -dnl SOSXXX:SAC_ASSERT_DEF([openssl libraries]) - - -if test "$with_openssl" = no ;then - : # No openssl -else - - if test "$with_openssl" = "pkg-config" ; then - PKG_CHECK_MODULES(openssl, openssl, - [HAVE_TLS=1 HAVE_OPENSSL=1 LIBS="$openssl_LIBS $LIBS"], - [HAVE_OPENSSL=0]) - fi - - if test x$HAVE_OPENSSL = x1 ; then - AC_DEFINE([HAVE_LIBCRYPTO], 1, [Define to 1 if you have the `crypto' library (-lcrypto).]) - AC_DEFINE([HAVE_LIBSSL], 1, [Define to 1 if you have the `ssl' library (-lssl).]) - else - AC_CHECK_HEADERS([openssl/tls1.h], [ - HAVE_OPENSSL=1 HAVE_TLS=1 - - AC_CHECK_LIB(crypto, BIO_new,, - HAVE_OPENSSL=0 - AC_MSG_WARN(OpenSSL crypto library was not found)) - - AC_CHECK_LIB(ssl, TLSv1_method,, - HAVE_TLS=0 - AC_MSG_WARN(OpenSSL protocol library was not found)) - ],[AC_MSG_WARN(OpenSSL include files were not found)],[#include ]) - fi - - if test x$HAVE_OPENSSL = x1; then - AC_DEFINE([HAVE_OPENSSL], 1, [Define to 1 if you have OpenSSL]) - fi - - if test x$HAVE_TLS = x1; then - AC_DEFINE([HAVE_TLS], 1, [Define to 1 if you have TLS]) - fi -fi - -AM_CONDITIONAL(HAVE_TLS, test x$HAVE_TLS = x1) -]) diff --git a/libs/libblade/configure.ac b/libs/libblade/configure.ac deleted file mode 100644 index 3089dc534c..0000000000 --- a/libs/libblade/configure.ac +++ /dev/null @@ -1,302 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.59) -AC_INIT(libblade, 0.1, bugs@freeswitch.org) -AC_CONFIG_AUX_DIR(build) -AC_CONFIG_MACRO_DIR([build]) -AM_INIT_AUTOMAKE -AC_CONFIG_SRCDIR([src]) - -# disable checks -m4_defun([_LT_AC_LANG_CXX_CONFIG], [:]) -m4_defun([_LT_AC_LANG_F77_CONFIG], [:]) - -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -# Absolute source/build directory -blade_srcdir=`(cd $srcdir && pwd)` -blade_builddir=`pwd` -AC_SUBST(blade_srcdir) -AC_SUBST(blade_builddir) - -case $host in - *-openbsd*) - # OpenBSD's gunzip and friends don't like -d because its redundant, only gzip does - AC_PATH_PROGS(ZCAT, gzip) - ;; - *) - AC_PATH_PROGS(ZCAT, gunzip gzcat gzip zcat) - ;; -esac - -AC_PATH_PROGS(BZIP, bzip2) -AC_PATH_PROGS(XZ, xz) -AC_PATH_PROGS(TAR, gtar tar) -AC_PATH_PROGS(WGET, wget) -AC_PATH_PROGS(CURL, curl) -GETLIB="cd $blade_builddir/.. && ${SHELL} $blade_builddir/../../build/getlib.sh" -AC_SUBST(GETLIB) - -# Checks for programs. -AC_PROG_CC -AC_PROG_MAKE_SET -AC_PROG_LIBTOOL -AC_PROG_INSTALL - -# Optimize -AC_ARG_ENABLE(optimization, -[AC_HELP_STRING([--enable-optimization],[Set if you want us to add max optimising compiler flags])],[enable_optimizer="$enableval"],[enable_optimizer="no"]) - -if test "${enable_optimizer}" = "yes" ; then - AC_DEFINE([OPTIMZER],[],[Enable Optimization.]) - AX_CC_MAXOPT -fi - -# Enable debugging -AC_ARG_ENABLE(debug, -[AC_HELP_STRING([--enable-debug],[build with debug information])],[enable_debug="$enable_debug"],[enable_debug="no"]) - -if test "${enable_debug}" = "yes"; then - AC_DEFINE([DEBUG],[],[Enable extra debugging.]) -fi - -AM_CONDITIONAL([WANT_DEBUG],[test "${enable_debug}" = "yes"]) - -dnl check for the compiler used -AX_COMPILER_VENDOR - -case "$host" in - *-solaris2*) - if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then - AM_CFLAGS="-KPIC -DPIC" - AM_LDFLAGS="-R${prefix}/lib" - fi - ;; - *-darwin*) - if test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then - AM_CFLAGS="-DMACOSX" - fi - ;; - x86_64-unknown-linux-gnu) - AM_CFLAGS="-fPIC" - AM_LDFLAGS="" - ;; - i*6-unknown-linux-gnu) - AM_CFLAGS="-fpic" - AM_LDFLAGS="" - ;; - x86_64-*-freebsd*|amd64-*-freebsd*) - AM_CFLAGS="-fpic" - AM_LDFLAGS="" - ;; - i*6-*-freebsd*) - AM_CFLAGS="-fpic" - AM_LDFLAGS="" - ;; -esac - -AX_CFLAGS_WARN_ALL_ANSI - -AC_CHECK_LIB(rt, clock_gettime, [AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if you have clock_gettime()])]) -AC_CHECK_LIB(rt, clock_getres, [AC_DEFINE(HAVE_CLOCK_GETRES, 1, [Define if you have clock_getres()])]) -AC_CHECK_LIB(rt, clock_nanosleep, [AC_DEFINE(HAVE_CLOCK_NANOSLEEP, 1, [Define if you have clock_nanosleep()])]) -AC_CHECK_FUNCS([usleep]) - -# -# sched_setcheduler + round-robin scheduler prerequisites -# -AC_CHECK_HEADERS([sched.h byteswap.h sys/endian.h]) -AC_CHECK_DECL([SCHED_RR], - [AC_DEFINE([HAVE_SCHED_RR],[1],[SCHED_RR constant for sched_setscheduler])],, - [#ifdef HAVE_SCHED_H - #include - #endif]) -AC_CHECK_FUNCS([sched_setscheduler memmem]) - -if test "x${ac_cv_func_sched_setscheduler}" = "xyes" -a \ - "x${ac_cv_have_decl_SCHED_RR}" = "xyes" -then - AC_DEFINE([USE_SCHED_SETSCHEDULER],[1],[Enable round-robin scheduler using sched_setscheduler]) - AM_CFLAGS="${AM_CFLAGS} -DUSE_SCHED_SETSCHEDULER=1" -fi - - - -# -# gcc visibility cflag checks -# -AC_ARG_ENABLE([visibility], - [AS_HELP_STRING([--disable-visibility], [Disable or enable API visibility support (default: use if available)])], - [enable_visibility="${enableval}"], - [enable_visibility="detect"] -) -HAVE_VISIBILITY="no" - -if test "x${enable_visibility}" != "xno" ; then - - case "${ax_cv_c_compiler_vendor}" in - gnu) - save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} -fvisibility=hidden" - AC_MSG_CHECKING([whether the compiler supports -fvisibility=hidden]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [int foo __attribute__ ((visibility("default")));], - [;] - )], - - [AC_MSG_RESULT([yes]) - AM_CFLAGS="${AM_CFLAGS} -DKS_API_VISIBILITY=1 -fvisibility=hidden" - AC_DEFINE([HAVE_VISIBILITY], [1], [GCC visibility support available]) - HAVE_VISIBILITY="yes"], - - [AC_MSG_RESULT([no])] - ) - CFLAGS="${save_CFLAGS}" - ;; - - sun) - save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} -xldscope=hidden" - AC_MSG_CHECKING([whether the compiler supports -xldscope=hidden]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [int foo __attribute__ ((visibility("default")));], - [;] - )], - - [AC_MSG_RESULT([yes]) - AM_CFLAGS="${AM_CFLAGS} -DKS_API_VISIBILITY=1 -xldscope=hidden" - AC_DEFINE([HAVE_VISIBILITY], [1], [SUNCC visibility support available]) - HAVE_VISIBILITY="yes"], - - [AC_MSG_RESULT([no])] - ) - CFLAGS="${save_CFLAGS}" - ;; - - *) - if test "x${enable_visibility}" = "xyes" ; then - AC_MSG_ERROR([Non-GNU / SUN compilers are currently unsupported]) - else - AC_MSG_WARN([Non-GNU / SUN compilers are currently unsupported]) - fi - ;; - esac - - # - # visibility explicitly requested but not supported by this compiler => error - # - if test "x${enable_visibility}" = "xyes" -a "x${HAVE_VISIBILITY}" = "xno" ; then - AC_MSG_ERROR([API visibility not supported by this compiler]) - fi -fi - -AM_CFLAGS="${AM_CFLAGS} -Werror" - -# Checks for header files. -AC_HEADER_DIRENT -AC_HEADER_STDC - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_TYPE_SIZE_T -AC_HEADER_TIME -AC_STRUCT_TM - -# Checks for library functions. -AC_PROG_GCC_TRADITIONAL -AC_FUNC_MALLOC -AC_TYPE_SIGNAL -AC_FUNC_STRFTIME - -AC_CHECK_LIB(pthread, pthread_setschedparam, [ -AC_DEFINE(HAVE_PTHREAD_SETSCHEDPARAM, 1, [Define if you have pthread_setschedparam()]) -AM_CFLAGS="${AM_CFLAGS} -DHAVE_PTHREAD_SETSCHEDPARAM=1" -]) - -AC_C_BIGENDIAN(AC_DEFINE([__BYTE_ORDER],__BIG_ENDIAN,[Big Endian]),AC_DEFINE([__BYTE_ORDER],__LITTLE_ENDIAN,[Little Endian])) -AC_DEFINE([__LITTLE_ENDIAN],1234,[for the places where it is not defined]) -AC_DEFINE([__BIG_ENDIAN],4321,[for the places where it is not defined]) - -path_remove () { - echo "$1" | tr ':' '\n' | grep -Fxv "$2" | tr '\n' ':' | sed 's/:$//' -} -path_push_unique () { - x="$(eval echo \$$1)" - x="$(path_remove "$x" "$2")" - if test -z "$x"; then - eval export $1="$2" - else - eval export $1="$2:$x" - fi -} - -case $host in - *-darwin*) - path_push_unique PKG_CONFIG_PATH /usr/local/opt/openssl/lib/pkgconfig - ;; -esac - -SAC_OPENSSL - -if test x$HAVE_OPENSSL = x1; then - openssl_CFLAGS="$openssl_CFLAGS -DHAVE_OPENSSL"; - AM_CFLAGS="${AM_CFLAGS} -DHAVE_OPENSSL" -else - AC_MSG_ERROR([OpenSSL and associated developement headers required]) -fi - -PKG_CHECK_MODULES([SODIUM], [libsodium >= 1.0.0],[AC_MSG_RESULT([yes])],[AC_MSG_ERROR([libsodium is required])]) -PKG_CHECK_MODULES([LIBKS], [libks >= 0.1],[AC_MSG_RESULT([yes])],[AC_MSG_WARN([libks is required, but not found.])]) -PKG_CHECK_MODULES([PCRE], [libpcre >= 7.8]) - -# Enable clang address sanitizer bit build -AC_ARG_ENABLE(address_sanitizer, - [AC_HELP_STRING([--enable-address-sanitizer],[build with address sanitizer])], - [enable_address_sanitizer="$enable_address_sanitizer"], - [enable_address_sanitizer="no"]) - -if test "${enable_address_sanitizer}" = "yes"; then - AM_CFLAGS="${AM_CFLAGS} -fsanitize=address -fno-omit-frame-pointer" - AM_CXXFLAGS="${AM_CXXFLAGS} -fsanitize=address -fno-omit-frame-pointer" - AM_LDFLAGS="${AM_LDFLAGS} -fsanitize=address" -fi - -AC_ARG_WITH([libks], - AS_HELP_STRING([--with-libks=DIR],[libks location @<:@/usr/src/freeswitch/libs/libks/@:>@]), - [with_libks="$withval"]) - -if test "x$with_libks" != "x"; then - LIBKS_LIBS="-L${with_libks} -L${with_libks}/.libs/ -lks" - LIBKS_CFLAGS="-I${with_libks}/src/include" -fi - - -#TODO: If LIBKS_CFLAGS is not defined and --with-libks is not defined, then check if ../libks/libks.la exists, and if so then use that path as a fallback -if test "${LIBKS_CFLAGS}" = ""; then - AC_CHECK_FILE([../libks/libks.la], - AC_MSG_WARN([local development version of libks is being used. This is probably not portable.]) - LIBKS_CFLAGS="-I`pwd`/../libks/src/include" - LIBKS_LIBS="-L`pwd`/../libks/.libs/ -lks", - AC_MSG_WARN([libks cannot be found.])) -fi - -AM_CPPFLAGS="-I./src -I./src/include ${LIBKS_CFLAGS} ${openssl_CFLAGS} ${SODIUM_CFLAGS}" -AM_LDFLAGS="${AM_LDFLAGS} ${LIBKS_LIBS} ${openssl_LIBS} ${SODIUM_LIBS}" - -AC_SUBST([AM_CFLAGS]) -AC_SUBST([AM_CPPFLAGS]) -AC_SUBST([AM_CXXDFLAGS]) -AC_SUBST([AM_LDFLAGS]) - -AC_CONFIG_FILES([Makefile - test/Makefile - switchblade/Makefile - libblade.pc - ../../build/getlib.sh -]) - -AC_OUTPUT diff --git a/libs/libblade/flows/flow1.json b/libs/libblade/flows/flow1.json deleted file mode 100644 index dec17eb4cd..0000000000 --- a/libs/libblade/flows/flow1.json +++ /dev/null @@ -1,227 +0,0 @@ ----> -GET /login HTTP/1.1 -Host: master.freeswitch.org -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ== -Sec-WebSocket-Protocol: blade-1.0 -Sec-WebSocket-Version: 13 - - -<--- -HTTP/1.1 101 Switching Protocols -Upgrade: websocket -Connection: Upgrade -Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo= -Sec-WebSocket-Protocol: blade-1.0 - - ----> CONNECT TO THE MASTER NODE -{ - "jsonrpc": "2.0", - "method": "BLADE.connect", - "params": { - "blade": "1.0", - "session-id": "", // optional, hint to reconnect to existing session - }, - "id": 1 -} - -<--- SUCCESS (TBD FAIL CASE) -{ - "jsonrpc": "2.0", - "id": 1, - "result": { - "blade": "1.0", - "connection-state": "connected", - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - "realm-list": [{"realm": "ls1.mydomain.com"}] - "allowed-protocol": ["BLADE"], - } -} - ----> REGISTER ADDITIONAL IDENTITY "foobar@ls1.mydomain.com/blah" -{ - "jsonrpc": "2.0", - "method": "BLADE.register", - "params": { - "identity": "foobar", - "realm": "ls1.mydomain.com", - "resource": "blah", - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - }, - "id": 2 -} - -<--- SUCCESS (TBD FAIL CASE) messages for this foobar IDENTITY will now go to this node. - { - "jsonrpc": "2.0", - "id": 2, - "result": { - "identity": "foobar", - "realm": "ls1.mydomain.com", - "resource": "blah", - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - } - } - ----> REGISTER SUBDOMAIN "myspace.ls1.mydomain.com" -{ - "jsonrpc": "2.0", - "method": "BLADE.register", - "params": { - "sub-realm": "myspace", - "realm": "ls1.mydomain.com", - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - }, - "id": 3 -} - -<--- SUCCESS (TBD FAIL CASE) messages for any IDENTITY at "myspace.ls1.mydomain.com" will now go to this node. - { - "jsonrpc": "2.0", - "id": 3, - "result": { - "sub-realm": "myspace", - "realm": "ls1.mydomain.com", - "realm-list": [{"realm": "ls1.mydomain.com", "sub-realms": ["myspace"]}], - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - } - } - - - ----> PUBLISH API LSAPI "A single node must have exclusive access to the PROTOCOL's namespace with the master to publish" -// MAYBE ADD SCHEMA and method to fetch it. -{ - "jsonrpc": "2.0", - "method": "BLADE.publish", - "params": { - "protocol": "LSAPI", - "exclusive": true, - "realm": "ls1.mydomain.com", - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - }, - "id": 4 -} - - -<--- SUCCESS (TBD FAIL CASE) -{ - "jsonrpc": "2.0", - "id": 4, - "result": { - "protocol": "LSAPI", - "allowed-protocol": ["BLADE", "LSAPI"], - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - } -} - ----> Locate identities holding an api -// MAYBE ADD SCHEMA and method to fetch it. -{ - "jsonrpc": "2.0", - "method": "BLADE.locate", - "params": { - "protocol": "LSAPI", - "realm": "ls1.mydomain.com", - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - }, - "id": 4.1 -} - - -<--- SUCCESS (TBD FAIL CASE) -{ - "jsonrpc": "2.0", - "id": 4.1, - "result": { - "protocol": "LSAPI", - "realm": "ls1.mydomain.com", - "sub-realm": null, - "targets": ["b9acdce6-3ce6-42db-82fc-39bf37c7a2b1", "5b696e8d-9875-45a5-b347-3b9fc288bad3"], - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - } -} - - - ----> EXECUTE API -{ - "jsonrpc": "2.0", - "method": "BLADE.execute", - "params": { - "realm": "ls1.mydomain.com", - "protocol": "LSAPI", - "method": "LSAPI.ls", - "params": { - "path": "/tmp/testing" - } - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - }, - "id": 5 -} - -<--- SUCCESS (TBD FAIL CASE) -{ - "jsonrpc": "2.0", - "id": 5, - "result": { - "realm": "ls1.mydomain.com", - "protocol": "LSAPI", - "result": { - "listing": "-rw-r--r-- 1 root root 33881 May 3 17:22 blank_avatar.png\ndrwxr-xr-x 6 root root 4096 Oct 26 2016 dash.js\n-rw-r--r-- 1 root root 5266 May 3 17:20 foo.diff\n-rw-r--r-- 1 root root 485 May 3 17:22 ks.diff" - }, - - } -} - - -Endpoints subscribe to event channels on their Master. -If that Master is not the top tier Master, it in turn subscribes all of its distinct events to it's Master until it reaches the top tier. -When the Master is encounterd who holds a connection to the Controller for a particular protocol, the Master subscribes to that Controller. - ----> EVENT SUB -{ - "jsonrpc": "2.0", - "method": "BLADE.subscribe", - "params": { - "realm": "ls1.mydomain.com", - "protocol": "LSAPI", - "event-space": "LSAPI", - "params": { - "eventChannel": "someEvent", - "subParams": {"foo": "bar"} - } - "session-id": "5b696e8d-9875-45a5-b347-3b9fc288bad3", - "master-id": "5164f7f8-a6ca-4dd4-8f36-33db1dc9c35d", - }, - "id": 6 -} - -<--- SUCCESS (TBD FAIL CASE) -{ - "jsonrpc": "2.0", - "id": 6, - "result": { - "realm": "ls1.mydomain.com", - "protocol": "LSAPI", - "event-space": "LSAPI", - "result": { - "subscribedChannels": ["someEvent"], - "unauthorizedChannels": [], - "alreadySubscribedChannels": [] - }, - - } -} diff --git a/libs/libblade/libblade.pc.in b/libs/libblade/libblade.pc.in deleted file mode 100644 index d16a6c9aa7..0000000000 --- a/libs/libblade/libblade.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: @PACKAGE_NAME@ -Version: @PACKAGE_VERSION@ -Description: The switchblade library. - -Cflags: -I${includedir} -Libs: -L${libdir} -lblade diff --git a/libs/libblade/libblade.props b/libs/libblade/libblade.props deleted file mode 100644 index b4377683a3..0000000000 --- a/libs/libblade/libblade.props +++ /dev/null @@ -1,14 +0,0 @@ - - - - - - - - UNICODE;SIMCLIST_NO_DUMPRESTORE;_CRT_SECURE_NO_WARNINGS;KS_EXPORTS;%(PreprocessorDefinitions) - $(ProjectDir)\src\include;%(AdditionalIncludeDirectories) - 4711;4574;4100;4127;4668;4255;4706;4710;4820 - - - - \ No newline at end of file diff --git a/libs/libblade/libblade.sln b/libs/libblade/libblade.sln deleted file mode 100644 index 886fab69bd..0000000000 --- a/libs/libblade/libblade.sln +++ /dev/null @@ -1,552 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OPENSSL", "..\win32\Download OPENSSL.2015.vcxproj", "{D578E676-7EC8-4548-BD8B-845C635F14AD}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libeay32", "..\win32\openssl\libeay32.2015.vcxproj", "{D331904D-A00A-4694-A5A3-FCFF64AB5DBE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssleay32", "..\win32\openssl\ssleay32.2015.vcxproj", "{B4B62169-5AD4-4559-8707-3D933AC5DB39}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libks", "..\libks\libks.vcxproj", "{70D178D8-1100-4152-86C0-809A91CFF832}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libblade", "libblade.vcxproj", "{A89D6D18-6203-4149-9051-F8E798E7A3E7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libsodium", "..\win32\libsodium\libsodium.2015.vcxproj", "{A185B162-6CB6-4502-B03F-B56F7699A8D9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libconfig", "..\win32\libconfig\libconfig.2015.vcxproj", "{1A234565-926D-49B2-83E4-D56E0C38C9F2}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "switchblade", "switchblade\switchblade.vcxproj", "{8330E669-77F3-4F70-A275-6F7BABE050A7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testcli", "test\testcli.vcxproj", "{CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testcon", "test\testcon.vcxproj", "{D67EEF66-B323-4BCF-9E3C-3A640B9949B7}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "openssl", "..\win32\openssl\openssl.2015.vcxproj", "{25BD39B1-C8BF-4676-A738-9CABD9C6BC79}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "civetweb", "..\win32\civetweb\civetweb.2015.vcxproj", "{1FAAE8B0-C134-436D-9B13-74C16517FC03}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "duktape_lib", "..\win32\civetweb\duktape_lib.vcxproj", "{0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}" - ProjectSection(ProjectDependencies) = postProject - {B9B7455D-F109-42BD-AD0A-98489B53FCF3} = {B9B7455D-F109-42BD-AD0A-98489B53FCF3} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "lua_lib", "..\win32\civetweb\lua_lib.vcxproj", "{8F5E5D77-D269-4665-9E27-1045DA6CF0D8}" - ProjectSection(ProjectDependencies) = postProject - {B9B7455D-F109-42BD-AD0A-98489B53FCF3} = {B9B7455D-F109-42BD-AD0A-98489B53FCF3} - EndProjectSection -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libconfig", "..\win32\Download libconfig.2015.vcxproj", "{4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download libsodium", "..\win32\Download libsodium.2015.vcxproj", "{96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download civetweb", "..\win32\Download civetweb.2015.vcxproj", "{B9B7455D-F109-42BD-AD0A-98489B53FCF3}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download PCRE", "..\win32\Download PCRE.2015.vcxproj", "{B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre", "..\win32\pcre\libpcre.2015.vcxproj", "{8D04B550-D240-4A44-8A18-35DA3F7038D9}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libpcre Generate pcre_chartables.c", "..\win32\pcre\pcre_chartables.c.2015.vcxproj", "{1CED5987-A529-46DC-B30F-870D85FF9C94}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug DLL|x64 = Debug DLL|x64 - Debug DLL|x86 = Debug DLL|x86 - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - DebugDLL|x64 = DebugDLL|x64 - DebugDLL|x86 = DebugDLL|x86 - Release DLL|x64 = Release DLL|x64 - Release DLL|x86 = Release DLL|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - ReleaseDLL|x64 = ReleaseDLL|x64 - ReleaseDLL|x86 = ReleaseDLL|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug DLL|x64.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug DLL|x64.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug DLL|x86.Build.0 = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.ActiveCfg = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.Build.0 = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x86.ActiveCfg = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x86.Build.0 = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.DebugDLL|x64.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.DebugDLL|x64.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.DebugDLL|x86.Build.0 = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release DLL|x64.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release DLL|x64.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release DLL|x86.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release DLL|x86.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x86.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x86.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.ReleaseDLL|x64.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.ReleaseDLL|x64.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.ReleaseDLL|x86.Build.0 = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug DLL|x64.ActiveCfg = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug DLL|x64.Build.0 = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug DLL|x86.Build.0 = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.ActiveCfg = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.Build.0 = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x86.ActiveCfg = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x86.Build.0 = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.DebugDLL|x64.ActiveCfg = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.DebugDLL|x64.Build.0 = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.DebugDLL|x86.Build.0 = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release DLL|x64.ActiveCfg = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release DLL|x64.Build.0 = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release DLL|x86.ActiveCfg = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release DLL|x86.Build.0 = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.ActiveCfg = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.Build.0 = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x86.ActiveCfg = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x86.Build.0 = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.ReleaseDLL|x64.Build.0 = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.ReleaseDLL|x86.Build.0 = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug DLL|x64.ActiveCfg = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug DLL|x64.Build.0 = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug DLL|x86.Build.0 = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.ActiveCfg = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.Build.0 = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x86.ActiveCfg = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x86.Build.0 = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.DebugDLL|x64.ActiveCfg = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.DebugDLL|x64.Build.0 = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.DebugDLL|x86.Build.0 = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release DLL|x64.ActiveCfg = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release DLL|x64.Build.0 = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release DLL|x86.ActiveCfg = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release DLL|x86.Build.0 = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.ActiveCfg = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.Build.0 = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x86.ActiveCfg = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x86.Build.0 = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.ReleaseDLL|x64.Build.0 = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.ReleaseDLL|x86.Build.0 = Release|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug DLL|x64.ActiveCfg = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug DLL|x64.Build.0 = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug DLL|x86.Build.0 = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x64.ActiveCfg = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x64.Build.0 = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x86.ActiveCfg = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x86.Build.0 = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.DebugDLL|x64.ActiveCfg = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.DebugDLL|x64.Build.0 = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.DebugDLL|x86.Build.0 = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release DLL|x64.ActiveCfg = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release DLL|x64.Build.0 = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release DLL|x86.ActiveCfg = Release|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release DLL|x86.Build.0 = Release|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x64.ActiveCfg = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x64.Build.0 = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x86.ActiveCfg = Release|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x86.Build.0 = Release|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.ReleaseDLL|x64.Build.0 = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.ReleaseDLL|x86.Build.0 = Release|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug DLL|x64.ActiveCfg = Debug|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug DLL|x64.Build.0 = Debug|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug DLL|x86.Build.0 = Debug|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug|x64.ActiveCfg = Debug|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug|x64.Build.0 = Debug|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug|x86.ActiveCfg = Debug|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Debug|x86.Build.0 = Debug|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.DebugDLL|x64.ActiveCfg = Debug|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.DebugDLL|x64.Build.0 = Debug|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.DebugDLL|x86.Build.0 = Debug|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release DLL|x64.ActiveCfg = Release|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release DLL|x64.Build.0 = Release|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release DLL|x86.ActiveCfg = Release|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release DLL|x86.Build.0 = Release|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release|x64.ActiveCfg = Release|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release|x64.Build.0 = Release|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release|x86.ActiveCfg = Release|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.Release|x86.Build.0 = Release|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.ReleaseDLL|x64.Build.0 = Release|x64 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {A89D6D18-6203-4149-9051-F8E798E7A3E7}.ReleaseDLL|x86.Build.0 = Release|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug DLL|x64.ActiveCfg = Debug|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug DLL|x64.Build.0 = Debug|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug DLL|x86.ActiveCfg = DebugDLL|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug DLL|x86.Build.0 = DebugDLL|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug|x64.ActiveCfg = Debug|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug|x64.Build.0 = Debug|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug|x86.ActiveCfg = Debug|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Debug|x86.Build.0 = Debug|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.DebugDLL|x64.Build.0 = DebugDLL|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.DebugDLL|x86.Build.0 = DebugDLL|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release DLL|x64.ActiveCfg = Release|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release DLL|x64.Build.0 = Release|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release DLL|x86.ActiveCfg = ReleaseDLL|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release DLL|x86.Build.0 = ReleaseDLL|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release|x64.ActiveCfg = Release|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release|x64.Build.0 = Release|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release|x86.ActiveCfg = Release|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.Release|x86.Build.0 = Release|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32 - {A185B162-6CB6-4502-B03F-B56F7699A8D9}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug DLL|x64.ActiveCfg = Debug|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug DLL|x64.Build.0 = Debug|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug DLL|x86.ActiveCfg = DebugDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug DLL|x86.Build.0 = DebugDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug|x64.ActiveCfg = Debug|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug|x64.Build.0 = Debug|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug|x86.ActiveCfg = Debug|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Debug|x86.Build.0 = Debug|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.DebugDLL|x64.ActiveCfg = DebugDLL|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.DebugDLL|x64.Build.0 = DebugDLL|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.DebugDLL|x86.ActiveCfg = DebugDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.DebugDLL|x86.Build.0 = DebugDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release DLL|x64.ActiveCfg = Release|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release DLL|x64.Build.0 = Release|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release DLL|x86.ActiveCfg = ReleaseDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release DLL|x86.Build.0 = ReleaseDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release|x64.ActiveCfg = Release|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release|x64.Build.0 = Release|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release|x86.ActiveCfg = Release|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.Release|x86.Build.0 = Release|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.ReleaseDLL|x64.ActiveCfg = ReleaseDLL|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.ReleaseDLL|x64.Build.0 = ReleaseDLL|x64 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.ReleaseDLL|x86.ActiveCfg = ReleaseDLL|Win32 - {1A234565-926D-49B2-83E4-D56E0C38C9F2}.ReleaseDLL|x86.Build.0 = ReleaseDLL|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug DLL|x64.ActiveCfg = Debug|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug DLL|x64.Build.0 = Debug|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug DLL|x86.Build.0 = Debug|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x64.ActiveCfg = Debug|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x64.Build.0 = Debug|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x86.ActiveCfg = Debug|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Debug|x86.Build.0 = Debug|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x64.ActiveCfg = Debug|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x64.Build.0 = Debug|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.DebugDLL|x86.Build.0 = Debug|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release DLL|x64.ActiveCfg = Release|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release DLL|x64.Build.0 = Release|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release DLL|x86.ActiveCfg = Release|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release DLL|x86.Build.0 = Release|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x64.ActiveCfg = Release|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x64.Build.0 = Release|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x86.ActiveCfg = Release|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.Release|x86.Build.0 = Release|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x64.Build.0 = Release|x64 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {8330E669-77F3-4F70-A275-6F7BABE050A7}.ReleaseDLL|x86.Build.0 = Release|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug DLL|x64.ActiveCfg = Debug|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug DLL|x64.Build.0 = Debug|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug DLL|x86.Build.0 = Debug|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug|x64.ActiveCfg = Debug|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug|x64.Build.0 = Debug|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug|x86.ActiveCfg = Debug|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Debug|x86.Build.0 = Debug|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.DebugDLL|x64.ActiveCfg = Debug|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.DebugDLL|x64.Build.0 = Debug|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.DebugDLL|x86.Build.0 = Debug|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release DLL|x64.ActiveCfg = Release|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release DLL|x64.Build.0 = Release|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release DLL|x86.ActiveCfg = Release|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release DLL|x86.Build.0 = Release|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release|x64.ActiveCfg = Release|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release|x64.Build.0 = Release|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release|x86.ActiveCfg = Release|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.Release|x86.Build.0 = Release|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.ReleaseDLL|x64.Build.0 = Release|x64 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5}.ReleaseDLL|x86.Build.0 = Release|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug DLL|x64.ActiveCfg = Debug|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug DLL|x64.Build.0 = Debug|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug DLL|x86.Build.0 = Debug|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug|x64.ActiveCfg = Debug|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug|x64.Build.0 = Debug|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug|x86.ActiveCfg = Debug|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Debug|x86.Build.0 = Debug|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.DebugDLL|x64.ActiveCfg = Debug|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.DebugDLL|x64.Build.0 = Debug|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.DebugDLL|x86.Build.0 = Debug|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release DLL|x64.ActiveCfg = Release|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release DLL|x64.Build.0 = Release|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release DLL|x86.ActiveCfg = Release|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release DLL|x86.Build.0 = Release|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release|x64.ActiveCfg = Release|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release|x64.Build.0 = Release|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release|x86.ActiveCfg = Release|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.Release|x86.Build.0 = Release|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.ReleaseDLL|x64.Build.0 = Release|x64 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7}.ReleaseDLL|x86.Build.0 = Release|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug DLL|x64.ActiveCfg = Debug|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug DLL|x64.Build.0 = Debug|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug DLL|x86.Build.0 = Debug|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.ActiveCfg = Debug|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x64.Build.0 = Debug|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x86.ActiveCfg = Debug|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Debug|x86.Build.0 = Debug|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.DebugDLL|x64.ActiveCfg = Debug|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.DebugDLL|x64.Build.0 = Debug|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.DebugDLL|x86.Build.0 = Debug|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release DLL|x64.ActiveCfg = Release|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release DLL|x64.Build.0 = Release|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release DLL|x86.ActiveCfg = Release|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release DLL|x86.Build.0 = Release|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.ActiveCfg = Release|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x64.Build.0 = Release|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x86.ActiveCfg = Release|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.Release|x86.Build.0 = Release|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.ReleaseDLL|x64.Build.0 = Release|x64 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {25BD39B1-C8BF-4676-A738-9CABD9C6BC79}.ReleaseDLL|x86.Build.0 = Release|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug DLL|x64.ActiveCfg = Debug|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug DLL|x64.Build.0 = Debug|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug DLL|x86.Build.0 = Debug|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug|x64.ActiveCfg = Debug|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug|x64.Build.0 = Debug|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug|x86.ActiveCfg = Debug|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Debug|x86.Build.0 = Debug|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.DebugDLL|x64.ActiveCfg = Debug|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.DebugDLL|x64.Build.0 = Debug|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.DebugDLL|x86.Build.0 = Debug|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release DLL|x64.ActiveCfg = Release|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release DLL|x64.Build.0 = Release|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release DLL|x86.ActiveCfg = Release|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release DLL|x86.Build.0 = Release|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release|x64.ActiveCfg = Release|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release|x64.Build.0 = Release|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release|x86.ActiveCfg = Release|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.Release|x86.Build.0 = Release|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.ReleaseDLL|x64.Build.0 = Release|x64 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {1FAAE8B0-C134-436D-9B13-74C16517FC03}.ReleaseDLL|x86.Build.0 = Release|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug DLL|x64.ActiveCfg = Debug|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug DLL|x64.Build.0 = Debug|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug DLL|x86.Build.0 = Debug|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug|x64.ActiveCfg = Debug|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug|x64.Build.0 = Debug|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug|x86.ActiveCfg = Debug|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Debug|x86.Build.0 = Debug|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.DebugDLL|x64.ActiveCfg = Debug|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.DebugDLL|x64.Build.0 = Debug|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.DebugDLL|x86.Build.0 = Debug|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release DLL|x64.ActiveCfg = Release|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release DLL|x64.Build.0 = Release|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release DLL|x86.ActiveCfg = Release|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release DLL|x86.Build.0 = Release|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release|x64.ActiveCfg = Release|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release|x64.Build.0 = Release|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release|x86.ActiveCfg = Release|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.Release|x86.Build.0 = Release|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.ReleaseDLL|x64.Build.0 = Release|x64 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {0A11689C-DB6A-4BF6-97B2-AD32DB863FBD}.ReleaseDLL|x86.Build.0 = Release|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug DLL|x64.ActiveCfg = Debug|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug DLL|x64.Build.0 = Debug|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug DLL|x86.Build.0 = Debug|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug|x64.ActiveCfg = Debug|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug|x64.Build.0 = Debug|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug|x86.ActiveCfg = Debug|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Debug|x86.Build.0 = Debug|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.DebugDLL|x64.ActiveCfg = Debug|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.DebugDLL|x64.Build.0 = Debug|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.DebugDLL|x86.Build.0 = Debug|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release DLL|x64.ActiveCfg = Release|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release DLL|x64.Build.0 = Release|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release DLL|x86.ActiveCfg = Release|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release DLL|x86.Build.0 = Release|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release|x64.ActiveCfg = Release|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release|x64.Build.0 = Release|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release|x86.ActiveCfg = Release|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.Release|x86.Build.0 = Release|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.ReleaseDLL|x64.Build.0 = Release|x64 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {8F5E5D77-D269-4665-9E27-1045DA6CF0D8}.ReleaseDLL|x86.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug DLL|x64.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug DLL|x64.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug DLL|x86.Build.0 = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug|x64.ActiveCfg = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug|x64.Build.0 = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug|x86.ActiveCfg = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Debug|x86.Build.0 = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.DebugDLL|x64.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.DebugDLL|x64.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.DebugDLL|x86.Build.0 = Debug|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release DLL|x64.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release DLL|x64.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release DLL|x86.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release DLL|x86.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release|x64.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release|x64.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release|x86.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.Release|x86.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.ReleaseDLL|x64.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.ReleaseDLL|x64.Build.0 = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA}.ReleaseDLL|x86.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug DLL|x64.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug DLL|x64.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug DLL|x86.Build.0 = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug|x64.ActiveCfg = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug|x64.Build.0 = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug|x86.ActiveCfg = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Debug|x86.Build.0 = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.DebugDLL|x64.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.DebugDLL|x64.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.DebugDLL|x86.Build.0 = Debug|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release DLL|x64.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release DLL|x64.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release DLL|x86.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release DLL|x86.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release|x64.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release|x64.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release|x86.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.Release|x86.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.ReleaseDLL|x64.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.ReleaseDLL|x64.Build.0 = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D}.ReleaseDLL|x86.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug DLL|x64.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug DLL|x64.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug DLL|x86.Build.0 = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug|x64.ActiveCfg = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug|x64.Build.0 = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug|x86.ActiveCfg = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Debug|x86.Build.0 = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.DebugDLL|x64.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.DebugDLL|x64.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.DebugDLL|x86.Build.0 = Debug|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release DLL|x64.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release DLL|x64.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release DLL|x86.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release DLL|x86.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release|x64.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release|x64.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release|x86.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.Release|x86.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.ReleaseDLL|x64.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.ReleaseDLL|x64.Build.0 = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {B9B7455D-F109-42BD-AD0A-98489B53FCF3}.ReleaseDLL|x86.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug DLL|x64.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug DLL|x64.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug DLL|x86.Build.0 = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug|x64.ActiveCfg = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug|x64.Build.0 = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug|x86.ActiveCfg = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Debug|x86.Build.0 = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.DebugDLL|x64.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.DebugDLL|x64.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.DebugDLL|x86.Build.0 = Debug|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release DLL|x64.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release DLL|x64.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release DLL|x86.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release DLL|x86.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release|x64.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release|x64.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release|x86.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.Release|x86.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.ReleaseDLL|x64.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.ReleaseDLL|x64.Build.0 = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {B1E7E876-347F-4DC9-9BEA-D1AFBD9DFF8A}.ReleaseDLL|x86.Build.0 = Release|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug DLL|x64.ActiveCfg = Debug DLL|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug DLL|x64.Build.0 = Debug DLL|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug DLL|x86.ActiveCfg = Debug DLL|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug DLL|x86.Build.0 = Debug DLL|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.ActiveCfg = Debug|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x64.Build.0 = Debug|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x86.ActiveCfg = Debug|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Debug|x86.Build.0 = Debug|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.DebugDLL|x64.ActiveCfg = Debug|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.DebugDLL|x64.Build.0 = Debug|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.DebugDLL|x86.Build.0 = Debug|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release DLL|x64.ActiveCfg = Release DLL|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release DLL|x64.Build.0 = Release DLL|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release DLL|x86.ActiveCfg = Release DLL|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release DLL|x86.Build.0 = Release DLL|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.ActiveCfg = Release|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x64.Build.0 = Release|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x86.ActiveCfg = Release|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.Release|x86.Build.0 = Release|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.ReleaseDLL|x64.Build.0 = Release|x64 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {8D04B550-D240-4A44-8A18-35DA3F7038D9}.ReleaseDLL|x86.Build.0 = Release|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug DLL|x64.ActiveCfg = Debug|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug DLL|x64.Build.0 = Debug|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug DLL|x86.ActiveCfg = Debug|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug DLL|x86.Build.0 = Debug|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.ActiveCfg = Debug|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x64.Build.0 = Debug|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x86.ActiveCfg = Debug|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Debug|x86.Build.0 = Debug|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.DebugDLL|x64.ActiveCfg = Debug|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.DebugDLL|x64.Build.0 = Debug|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.DebugDLL|x86.ActiveCfg = Debug|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.DebugDLL|x86.Build.0 = Debug|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release DLL|x64.ActiveCfg = Release|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release DLL|x64.Build.0 = Release|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release DLL|x86.ActiveCfg = Release|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release DLL|x86.Build.0 = Release|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.ActiveCfg = Release|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x64.Build.0 = Release|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x86.ActiveCfg = Release|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.Release|x86.Build.0 = Release|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.ReleaseDLL|x64.ActiveCfg = Release|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.ReleaseDLL|x64.Build.0 = Release|x64 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.ReleaseDLL|x86.ActiveCfg = Release|Win32 - {1CED5987-A529-46DC-B30F-870D85FF9C94}.ReleaseDLL|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libs/libblade/libblade.vcxproj b/libs/libblade/libblade.vcxproj deleted file mode 100644 index 40baad7dda..0000000000 --- a/libs/libblade/libblade.vcxproj +++ /dev/null @@ -1,246 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {A89D6D18-6203-4149-9051-F8E798E7A3E7} - Win32Proj - 8.1 - - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140 - Unicode - - - StaticLibrary - true - v140 - Unicode - - - StaticLibrary - false - v140 - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset - true - - - - - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset - true - - - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBKS_EXPORTS;CJSON_EXPORT_SYMBOLS;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - EnableAllWarnings - ProgramDatabase - Disabled - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702;4456;4242;4457;4459;4244;4324;4204;4388;4245;4267 - true - false - true - - - MachineX86 - true - Windows - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBKS_EXPORTS;CJSON_EXPORT_SYMBOLS;%(PreprocessorDefinitions) - MultiThreadedDLL - EnableAllWarnings - ProgramDatabase - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702;4456;4242;4457;4459;4244;4324;4204;4388;4245;4267 - true - - - MachineX86 - true - Windows - true - true - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - WIN32;_DEBUG;_WINDOWS;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - EditAndContinue - EnableAllWarnings - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702;4456;4242;4457;4459;4244;4324;4204;4388;4245;4267 - true - false - true - MultiThreadedDebugDLL - - - Windows - Debug - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - WIN32;NDEBUG;_WINDOWS;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - EnableAllWarnings - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702;4456;4242;4457;4459;4244;4324;4204;4388;4245;4267 - true - MultiThreadedDLL - - - Windows - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - {1faae8b0-c134-436d-9b13-74c16517fc03} - - - {1a234565-926d-49b2-83e4-d56e0c38c9f2} - - - {a185b162-6cb6-4502-b03f-b56f7699a8d9} - - - {8d04b550-d240-4a44-8a18-35da3f7038d9} - - - - - - \ No newline at end of file diff --git a/libs/libblade/libblade.vcxproj.filters b/libs/libblade/libblade.vcxproj.filters deleted file mode 100644 index 2c7dbb8b54..0000000000 --- a/libs/libblade/libblade.vcxproj.filters +++ /dev/null @@ -1,156 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/libs/libblade/src/bencode.c b/libs/libblade/src/bencode.c deleted file mode 100644 index 390c63bc29..0000000000 --- a/libs/libblade/src/bencode.c +++ /dev/null @@ -1,2683 +0,0 @@ -/* - * libbencodetools - * - * Written by Heikki Orsila and - * Janne Kulmala in 2011. - */ - -#include - -#include -#include -#include -#include -#include -#include -#include - -#define die(fmt, args...) do { fprintf(stderr, "bencode: fatal error: " fmt, ## args); abort(); } while (0) -#define warn(fmt, args...) do { fprintf(stderr, "bencode: warning: " fmt, ## args); } while (0) - -#define MAX_ALLOC (((size_t) -1) / sizeof(struct bencode *) / 2) -#define DICT_MAX_ALLOC (((size_t) -1) / sizeof(struct bencode_dict_node) / 2) - -struct ben_decode_ctx { - const char *data; - const size_t len; - size_t off; - int error; - int level; - char c; - int line; - struct bencode_type **types; -}; - -struct ben_encode_ctx { - char *data; - size_t size; - size_t pos; -}; - -/* - * Buffer size for fitting all unsigned long long and long long integers, - * assuming it is at most 64 bits. If long long is larger than 64 bits, - * an error is produced when too large an integer is converted. - */ -#define LONGLONGSIZE 21 - -static struct bencode *decode_printed(struct ben_decode_ctx *ctx); -static void inplace_ben_str(struct bencode_str *b, const char *s, size_t len); -static int resize_dict(struct bencode_dict *d, size_t newalloc); -static int resize_list(struct bencode_list *list, size_t newalloc); -static int unpack(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl); -static struct bencode *pack(struct ben_decode_ctx *ctx, va_list *vl); - -static size_t type_size(int type) -{ - switch (type) { - case BENCODE_BOOL: - return sizeof(struct bencode_bool); - case BENCODE_DICT: - return sizeof(struct bencode_dict); - case BENCODE_INT: - return sizeof(struct bencode_int); - case BENCODE_LIST: - return sizeof(struct bencode_list); - case BENCODE_STR: - return sizeof(struct bencode_str); - default: - die("Unknown type: %d\n", type); - } -} - -static void *alloc(int type) -{ - struct bencode *b = calloc(1, type_size(type)); - if (b == NULL) - return NULL; - b->type = type; - return b; -} - -void *ben_alloc_user(struct bencode_type *type) -{ - struct bencode_user *user = calloc(1, type->size); - if (user == NULL) - return NULL; - user->type = BENCODE_USER; - user->info = type; - return user; -} - -static int insufficient(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INSUFFICIENT; - return -1; -} - -static int invalid(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INVALID; - return -1; -} - -static int mismatch(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_MISMATCH; - return -1; -} - -void *ben_insufficient_ptr(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INSUFFICIENT; - return NULL; -} - -void *ben_invalid_ptr(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INVALID; - return NULL; -} - -void *ben_oom_ptr(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_NO_MEMORY; - return NULL; -} - -int ben_need_bytes(const struct ben_decode_ctx *ctx, size_t n) -{ - return ((ctx->off + n) <= ctx->len) ? 0 : -1; -} - -char ben_current_char(const struct ben_decode_ctx *ctx) -{ - return ctx->data[ctx->off]; -} - -const char *ben_current_buf(const struct ben_decode_ctx *ctx, size_t n) -{ - return ben_need_bytes(ctx, n) ? NULL : ctx->data + ctx->off; -} - -void ben_skip(struct ben_decode_ctx *ctx, size_t n) -{ - ctx->off += n; -} - -static struct bencode *internal_blob(void *data, size_t len) -{ - struct bencode_str *b = alloc(BENCODE_STR); - if (b == NULL) - return NULL; - b->s = data; - b->len = len; - assert(b->s[len] == 0); - return (struct bencode *) b; -} - -static void skip_to_next_line(struct ben_decode_ctx *ctx) -{ - for (; ctx->off < ctx->len; ctx->off++) { - if (ben_current_char(ctx) == '\n') { - ctx->line++; - ctx->off++; - break; - } - } -} - -static int seek_char(struct ben_decode_ctx *ctx) -{ - while (ctx->off < ctx->len) { - char c = ben_current_char(ctx); - if (isspace(c)) { - if (c == '\n') - ctx->line++; - ctx->off++; - } else if (c == '#') { - /* Skip comment */ - ctx->off++; - skip_to_next_line(ctx); - } else { - return 0; - } - } - return insufficient(ctx); -} - -/* - * Test if string 's' is located at current position. - * Increment current position and return 0 if the string matches. - * Returns -1 otherwise. The function avoids buffer overflow. - */ -static int try_match(struct ben_decode_ctx *ctx, const char *s) -{ - size_t n = strlen(s); - if (ben_need_bytes(ctx, n)) - return -1; - if (memcmp(ctx->data + ctx->off, s, n) != 0) - return -1; - ctx->off += n; - return 0; -} - -static int try_match_with_errors(struct ben_decode_ctx *ctx, const char *s) -{ - size_t n = strlen(s); - size_t left = ctx->len - ctx->off; - - assert(ctx->off <= ctx->len); - - if (left == 0) - return insufficient(ctx); - - if (left < n) { - if (memcmp(ctx->data + ctx->off, s, left) != 0) - return invalid(ctx); - return insufficient(ctx); - } - - if (memcmp(ctx->data + ctx->off, s, n) != 0) - return invalid(ctx); - - ctx->off += n; - return 0; -} - -int ben_allocate(struct bencode *b, size_t n) -{ - switch (b->type) { - case BENCODE_DICT: - return resize_dict(ben_dict_cast(b), n); - case BENCODE_LIST: - return resize_list(ben_list_cast(b), n); - default: - die("ben_allocate(): Unknown type %d\n", b->type); - } -} - -static struct bencode *clone_dict(const struct bencode_dict *d) -{ - struct bencode *key; - struct bencode *value; - struct bencode *newkey; - struct bencode *newvalue; - size_t pos; - struct bencode *newdict = ben_dict(); - if (newdict == NULL) - return NULL; - ben_dict_for_each(key, value, pos, (const struct bencode *) d) { - newkey = ben_clone(key); - newvalue = ben_clone(value); - if (newkey == NULL || newvalue == NULL) { - ben_free(newkey); - ben_free(newvalue); - goto error; - } - if (ben_dict_set(newdict, newkey, newvalue)) { - ben_free(newkey); - ben_free(newvalue); - goto error; - } - newkey = NULL; - newvalue = NULL; - } - return newdict; - -error: - ben_free(newdict); - return NULL; -} - -static struct bencode *clone_list(const struct bencode_list *list) -{ - struct bencode *value; - struct bencode *newvalue; - size_t pos; - struct bencode *newlist = ben_list(); - if (newlist == NULL) - return NULL; - ben_list_for_each(value, pos, (const struct bencode *) list) { - newvalue = ben_clone(value); - if (newvalue == NULL) - goto error; - if (ben_list_append(newlist, newvalue)) { - ben_free(newvalue); - goto error; - } - newvalue = NULL; - } - return newlist; - -error: - ben_free(newlist); - return NULL; -} - -static struct bencode *clone_str(const struct bencode_str *s) -{ - return ben_blob(s->s, s->len); -} - -static struct bencode *share_dict(const struct bencode_dict *d) -{ - struct bencode *newdict = ben_dict(); - if (newdict == NULL) - return NULL; - memcpy(newdict, d, sizeof(*d)); - ((struct bencode_dict *) newdict)->shared = 1; - return newdict; -} - -static struct bencode *share_list(const struct bencode_list *list) -{ - struct bencode *newlist = ben_list(); - if (newlist == NULL) - return NULL; - memcpy(newlist, list, sizeof(*list)); - ((struct bencode_list *) newlist)->shared = 1; - return newlist; -} - -struct bencode *ben_clone(const struct bencode *b) -{ - switch (b->type) { - case BENCODE_BOOL: - return ben_bool(ben_bool_const_cast(b)->b); - case BENCODE_DICT: - return clone_dict(ben_dict_const_cast(b)); - case BENCODE_INT: - return ben_int(ben_int_const_cast(b)->ll); - case BENCODE_LIST: - return clone_list(ben_list_const_cast(b)); - case BENCODE_STR: - return clone_str(ben_str_const_cast(b)); - default: - die("Invalid type %c\n", b->type); - } -} - -struct bencode *ben_shared_clone(const struct bencode *b) -{ - switch (b->type) { - case BENCODE_DICT: - return share_dict(ben_dict_const_cast(b)); - break; - case BENCODE_LIST: - return share_list(ben_list_const_cast(b)); - break; - default: - return ben_clone(b); - } -} - -static int cmp_dict(const struct bencode *a, const struct bencode *b) -{ - size_t len = ben_dict_len(a); - size_t pos; - struct bencode *key; - struct bencode *va; - struct bencode *vb; - int ret = 0; - struct bencode_keyvalue *pairs; - - if (len != ben_dict_len(b)) { - /* Returning any non-zero value is allowed */ - return (len < ben_dict_len(b)) ? -1 : 1; - } - - pairs = ben_dict_ordered_items(a); - for (pos = 0; pos < len; pos++) { - key = pairs[pos].key; - va = pairs[pos].value; - vb = ben_dict_get(b, key); - if (vb == NULL) { - /* Returning any non-zero value is allowed */ - ret = (a < b) ? -1 : 1; - break; - } - ret = ben_cmp(va, vb); - if (ret) - break; - } - - free(pairs); - return ret; -} - -static int cmp_list(const struct bencode *a, const struct bencode *b) -{ - const struct bencode_list *la; - const struct bencode_list *lb; - struct bencode *va; - struct bencode *vb; - size_t cmplen; - size_t i; - int ret; - - la = ben_list_const_cast(a); - lb = ben_list_const_cast(b); - cmplen = (la->n <= lb->n) ? la->n : lb->n; - - for (i = 0; i < cmplen; ++i) { - va = ben_list_get(a, i); - vb = ben_list_get(b, i); - ret = ben_cmp(va, vb); - if (ret) - return ret; - } - if (la->n != lb->n) - return (la->n < lb->n) ? -1 : 1; - return 0; -} - -int ben_cmp(const struct bencode *a, const struct bencode *b) -{ - size_t cmplen; - int ret; - const struct bencode_int *ia; - const struct bencode_int *ib; - const struct bencode_str *sa; - const struct bencode_str *sb; - const struct bencode_user *ua; - const struct bencode_user *ub; - - if (a->type != b->type) - return (a->type == BENCODE_INT) ? -1 : 1; - - switch (a->type) { - case BENCODE_INT: - ia = ben_int_const_cast(a); - ib = ben_int_const_cast(b); - if (ia->ll < ib->ll) - return -1; - if (ib->ll < ia->ll) - return 1; - return 0; - case BENCODE_STR: - sa = ben_str_const_cast(a); - sb = ben_str_const_cast(b); - cmplen = (sa->len <= sb->len) ? sa->len : sb->len; - ret = memcmp(sa->s, sb->s, cmplen); - if (ret) - return ret < 0 ? -1 : 1; - if (sa->len != sb->len) - return (sa->len < sb->len) ? -1 : 1; - return 0; - case BENCODE_DICT: - return cmp_dict(a, b); - case BENCODE_LIST: - return cmp_list(a, b); - case BENCODE_USER: - ua = ben_user_const_cast(a); - ub = ben_user_const_cast(b); - if (ua->info != ub->info) - return (a < b) ? -1 : 1; - return ua->info->cmp(a, b); - default: - die("Invalid type %c\n", b->type); - } -} - -int ben_cmp_with_str(const struct bencode *a, const char *s) -{ - struct bencode_str b; - inplace_ben_str(&b, s, strlen(s)); - return ben_cmp(a, (struct bencode *) &b); -} - -int ben_cmp_qsort(const void *a, const void *b) -{ - const struct bencode *akey = ((const struct bencode_keyvalue *) a)->key; - const struct bencode *bkey = ((const struct bencode_keyvalue *) b)->key; - return ben_cmp(akey, bkey); -} - -static struct bencode *decode_bool(struct ben_decode_ctx *ctx) -{ - struct bencode_bool *b; - char value; - char c; - if (ben_need_bytes(ctx, 2)) - return ben_insufficient_ptr(ctx); - ctx->off++; - - c = ben_current_char(ctx); - if (c != '0' && c != '1') - return ben_invalid_ptr(ctx); - - value = (c == '1'); - b = alloc(BENCODE_BOOL); - if (b == NULL) - return ben_oom_ptr(ctx); - - b->b = value; - ctx->off++; - return (struct bencode *) b; -} - -static size_t hash_bucket(long long hash, const struct bencode_dict *d) -{ - return hash & (d->alloc - 1); -} - -static size_t hash_bucket_head(long long hash, const struct bencode_dict *d) -{ - if (d->buckets == NULL) - return -1; - return d->buckets[hash_bucket(hash, d)]; -} - -static int resize_dict(struct bencode_dict *d, size_t newalloc) -{ - size_t *newbuckets; - struct bencode_dict_node *newnodes;; - size_t pos; - - if (newalloc == -1) { - if (d->alloc >= DICT_MAX_ALLOC) - return -1; - - if (d->alloc == 0) - newalloc = 4; - else - newalloc = d->alloc * 2; - } else { - size_t x; - if (newalloc < d->n || newalloc > DICT_MAX_ALLOC) - return -1; - /* Round to next power of two */ - x = 1; - while (x < newalloc) - x <<= 1; - assert(x >= newalloc); - newalloc = x; - if (newalloc > DICT_MAX_ALLOC) - return -1; - } - - /* size must be a power of two */ - assert((newalloc & (newalloc - 1)) == 0); - - newbuckets = realloc(d->buckets, sizeof(newbuckets[0]) * newalloc); - newnodes = realloc(d->nodes, sizeof(newnodes[0]) * newalloc); - if (newnodes == NULL || newbuckets == NULL) { - free(newnodes); - free(newbuckets); - return -1; - } - - d->alloc = newalloc; - d->buckets = newbuckets; - d->nodes = newnodes; - - /* Clear all buckets */ - memset(d->buckets, -1, d->alloc * sizeof(d->buckets[0])); - - /* Reinsert nodes into buckets */ - for (pos = 0; pos < d->n; pos++) { - struct bencode_dict_node *node = &d->nodes[pos]; - size_t bucket = hash_bucket(node->hash, d); - node->next = d->buckets[bucket]; - d->buckets[bucket] = pos; - } - - return 0; -} - -/* The string/binary object hash is copied from Python */ -static long long str_hash(const unsigned char *s, size_t len) -{ - long long hash; - size_t i; - if (len == 0) - return 0; - hash = s[0] << 7; - for (i = 0; i < len; i++) - hash = (1000003 * hash) ^ s[i]; - hash ^= len; - if (hash == -1) - hash = -2; - return hash; -} - -long long ben_str_hash(const struct bencode *b) -{ - const struct bencode_str *bstr = ben_str_const_cast(b); - const unsigned char *s = (unsigned char *) bstr->s; - return str_hash(s, bstr->len); -} - -long long ben_int_hash(const struct bencode *b) -{ - long long x = ben_int_const_cast(b)->ll; - return (x == -1) ? -2 : x; -} - -long long ben_hash(const struct bencode *b) -{ - switch (b->type) { - case BENCODE_INT: - return ben_int_hash(b); - case BENCODE_STR: - return ben_str_hash(b); - default: - die("hash: Invalid type: %d\n", b->type); - } -} - -static struct bencode *decode_dict(struct ben_decode_ctx *ctx) -{ - struct bencode *key; - struct bencode *lastkey = NULL; - struct bencode *value; - struct bencode_dict *d; - - d = alloc(BENCODE_DICT); - if (d == NULL) { - warn("Not enough memory for dict\n"); - return ben_oom_ptr(ctx); - } - - ctx->off++; - - while (ctx->off < ctx->len && ben_current_char(ctx) != 'e') { - key = ben_ctx_decode(ctx); - if (key == NULL) - goto error; - if (key->type != BENCODE_INT && key->type != BENCODE_STR) { - ben_free(key); - key = NULL; - ctx->error = BEN_INVALID; - warn("Invalid dict key type\n"); - goto error; - } - - if (lastkey != NULL && ben_cmp(lastkey, key) >= 0) { - ben_free(key); - key = NULL; - ctx->error = BEN_INVALID; - goto error; - } - - value = ben_ctx_decode(ctx); - if (value == NULL) { - ben_free(key); - key = NULL; - goto error; - } - - if (ben_dict_set((struct bencode *) d, key, value)) { - ben_free(key); - ben_free(value); - key = NULL; - value = NULL; - ctx->error = BEN_NO_MEMORY; - goto error; - } - - lastkey = key; - } - if (ctx->off >= ctx->len) { - ctx->error = BEN_INSUFFICIENT; - goto error; - } - - ctx->off++; - - return (struct bencode *) d; - -error: - ben_free((struct bencode *) d); - return NULL; -} - -static size_t find(const struct ben_decode_ctx *ctx, char c) -{ - char *match = memchr(ctx->data + ctx->off, c, ctx->len - ctx->off); - if (match == NULL) - return -1; - return (size_t) (match - ctx->data); -} - -/* off is the position of first number in */ -static int read_long_long(long long *ll, struct ben_decode_ctx *ctx, int c) -{ - char buf[LONGLONGSIZE]; /* fits all 64 bit integers */ - char *endptr; - size_t slen; - size_t pos = find(ctx, c); - - if (pos == -1) - return insufficient(ctx); - - slen = pos - ctx->off; - if (slen == 0 || slen >= sizeof buf) - return invalid(ctx); - - assert(slen < sizeof buf); - memcpy(buf, ctx->data + ctx->off, slen); - buf[slen] = 0; - - if (buf[0] != '-' && !isdigit(buf[0])) - return invalid(ctx); - - errno = 0; - *ll = strtoll(buf, &endptr, 10); - if (errno == ERANGE || *endptr != 0) - return invalid(ctx); - - /* - * Demand a unique encoding for all integers. - * Zero may not begin with a (minus) sign. - * Non-zero integers may not have leading zeros in the encoding. - */ - if (buf[0] == '-' && buf[1] == '0') - return invalid(ctx); - if (buf[0] == '0' && pos != (ctx->off + 1)) - return invalid(ctx); - - ctx->off = pos + 1; - return 0; -} - -static struct bencode *decode_int(struct ben_decode_ctx *ctx) -{ - struct bencode_int *b; - long long ll; - ctx->off++; - if (read_long_long(&ll, ctx, 'e')) - return NULL; - b = alloc(BENCODE_INT); - if (b == NULL) - return ben_oom_ptr(ctx); - b->ll = ll; - return (struct bencode *) b; -} - -static int resize_list(struct bencode_list *list, size_t newalloc) -{ - struct bencode **newvalues; - size_t newsize; - - if (newalloc == -1) { - if (list->alloc >= MAX_ALLOC) - return -1; - if (list->alloc == 0) - newalloc = 4; - else - newalloc = list->alloc * 2; - } else { - if (newalloc < list->n || newalloc > MAX_ALLOC) - return -1; - } - - newsize = sizeof(list->values[0]) * newalloc; - newvalues = realloc(list->values, newsize); - if (newvalues == NULL) - return -1; - list->alloc = newalloc; - list->values = newvalues; - return 0; -} - -static struct bencode *decode_list(struct ben_decode_ctx *ctx) -{ - struct bencode_list *l = alloc(BENCODE_LIST); - if (l == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (ctx->off < ctx->len && ben_current_char(ctx) != 'e') { - struct bencode *b = ben_ctx_decode(ctx); - if (b == NULL) - goto error; - if (ben_list_append((struct bencode *) l, b)) { - ben_free(b); - ctx->error = BEN_NO_MEMORY; - goto error; - } - } - - if (ctx->off >= ctx->len) { - ctx->error = BEN_INSUFFICIENT; - goto error; - } - - ctx->off++; - return (struct bencode *) l; - -error: - ben_free((struct bencode *) l); - return NULL; -} - -static size_t read_size_t(struct ben_decode_ctx *ctx, int c) -{ - long long ll; - size_t s; - if (read_long_long(&ll, ctx, c)) - return -1; - if (ll < 0) - return invalid(ctx); - /* - * Test that information is not lost when converting from long long - * to size_t - */ - s = (size_t) ll; - if (ll != (long long) s) - return invalid(ctx); - return s; -} - -static struct bencode *decode_str(struct ben_decode_ctx *ctx) -{ - struct bencode *b; - size_t datalen = read_size_t(ctx, ':'); /* Read the string length */ - if (datalen == -1) - return NULL; - - if (ben_need_bytes(ctx, datalen)) - return ben_insufficient_ptr(ctx); - - /* Allocate string structure and copy data into it */ - b = ben_blob(ctx->data + ctx->off, datalen); - ctx->off += datalen; - return b; -} - -struct bencode *ben_ctx_decode(struct ben_decode_ctx *ctx) -{ - char c; - struct bencode_type *type; - struct bencode *b; - ctx->level++; - if (ctx->level > 256) - return ben_invalid_ptr(ctx); - - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - - assert (ctx->off < ctx->len); - c = ben_current_char(ctx); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - b = decode_str(ctx); - break; - case 'b': - b = decode_bool(ctx); - break; - case 'd': - b = decode_dict(ctx); - break; - case 'i': - b = decode_int(ctx); - break; - case 'l': - b = decode_list(ctx); - break; - default: - if (ctx->types && (unsigned char) c < 128) { - type = ctx->types[(unsigned char) c]; - if (type) { - ctx->off++; - b = type->decode(ctx); - } else - return ben_invalid_ptr(ctx); - } else - return ben_invalid_ptr(ctx); - } - ctx->level--; - return b; -} - -struct bencode *ben_decode(const void *data, size_t len) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len}; - struct bencode *b = ben_ctx_decode(&ctx); - if (b != NULL && ctx.off != len) { - ben_free(b); - return NULL; - } - return b; -} - -struct bencode *ben_decode2(const void *data, size_t len, size_t *off, int *error) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len, .off = *off}; - struct bencode *b = ben_ctx_decode(&ctx); - *off = ctx.off; - if (error != NULL) { - assert((b != NULL) ^ (ctx.error != 0)); - *error = ctx.error; - } - return b; -} - -struct bencode *ben_decode3(const void *data, size_t len, size_t *off, int *error, struct bencode_type *types[128]) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len, .off = *off, - .types = types}; - struct bencode *b = ben_ctx_decode(&ctx); - *off = ctx.off; - if (error != NULL) { - assert((b != NULL) ^ (ctx.error != 0)); - *error = ctx.error; - } - return b; -} - -static struct bencode *decode_printed_bool(struct ben_decode_ctx *ctx) -{ - struct bencode *b; - int bval = -1; - - if (try_match(ctx, "True")) { - if (ben_need_bytes(ctx, 4)) - return ben_insufficient_ptr(ctx); - } else { - bval = 1; - } - - if (bval < 0) { - /* It's not 'True', so it can only be 'False'. Verify it. */ - if (try_match_with_errors(ctx, "False")) - return NULL; - bval = 0; - } - - assert(bval == 0 || bval == 1); - b = ben_bool(bval); - if (b == NULL) - return ben_oom_ptr(ctx); - return b; -} - -static struct bencode *decode_printed_dict(struct ben_decode_ctx *ctx) -{ - struct bencode *d = ben_dict(); - struct bencode *key = NULL; - struct bencode *value = NULL; - - if (d == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == '}') { - ctx->off++; - break; - } - - key = decode_printed(ctx); - if (key == NULL) - goto nullpath; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) != ':') - goto invalidpath; - ctx->off++; - - value = decode_printed(ctx); - if (value == NULL) - goto nullpath; - - if (ben_dict_set(d, key, value)) { - ben_free(key); - ben_free(value); - ben_free(d); - return ben_oom_ptr(ctx); - } - key = NULL; - value = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != '}') - goto invalidpath; - } - return d; - -invalidpath: - ben_free(key); - ben_free(value); - ben_free(d); - return ben_invalid_ptr(ctx); - -nullpath: - ben_free(key); - ben_free(value); - ben_free(d); - return NULL; -} - -static struct bencode *decode_printed_int(struct ben_decode_ctx *ctx) -{ - long long ll; - char buf[LONGLONGSIZE]; - char *end; - size_t pos = 0; - struct bencode *b; - int gotzero = 0; - int base = 10; - int neg = 0; - - if (ben_current_char(ctx) == '-') { - neg = 1; - ctx->off++; - } - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - - if (ben_current_char(ctx) == '0') { - buf[pos] = '0'; - pos++; - ctx->off++; - gotzero = 1; - } - - if (gotzero) { - if (ctx->off == ctx->len) { - ll = 0; - goto returnwithval; - } - if (ben_current_char(ctx) == 'x') { - pos = 0; - base = 16; - ctx->off++; - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - } else if (isdigit(ben_current_char(ctx))) { - base = 8; - } - } else { - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - } - - while (ctx->off < ctx->len && pos < sizeof buf) { - char c = ben_current_char(ctx); - if (base == 16) { - if (!isxdigit(c)) - break; - } else { - if (!isdigit(c)) - break; - } - buf[pos] = c; - pos++; - ctx->off++; - } - if (pos == 0 || pos == sizeof buf) - return ben_invalid_ptr(ctx); - buf[pos] = 0; - ll = strtoll(buf, &end, base); - if (*end != 0) - return ben_invalid_ptr(ctx); - -returnwithval: - if (neg) - ll = -ll; - b = ben_int(ll); - if (b == NULL) - return ben_oom_ptr(ctx); - return b; -} - -static struct bencode *decode_printed_list(struct ben_decode_ctx *ctx) -{ - struct bencode *l = ben_list(); - struct bencode *b = NULL; - - if (l == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ']') { - ctx->off++; - break; - } - b = decode_printed(ctx); - if (b == NULL) - goto nullpath; - if (ben_list_append(l, b)) { - ben_free(b); - ben_free(l); - return ben_oom_ptr(ctx); - } - b = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != ']') { - ben_free(l); - return ben_invalid_ptr(ctx); - } - } - return l; - -nullpath: - ben_free(b); - ben_free(l); - return NULL; -} - -static struct bencode *decode_printed_str(struct ben_decode_ctx *ctx) -{ - size_t pos; - char *s = NULL; - size_t len = 0; - char initial = ben_current_char(ctx); - struct bencode *b; - - ctx->off++; - pos = ctx->off; - while (pos < ctx->len) { - char c = ctx->data[pos]; - if (!isprint(c)) - return ben_invalid_ptr(ctx); - if (c == initial) - break; - len++; - pos++; - if (c != '\\') - continue; /* Normal printable char, e.g. 'a' */ - /* Handle '\\' */ - if (pos == ctx->len) - return ben_insufficient_ptr(ctx); - - c = ctx->data[pos]; - pos++; - if (c == 'x') { - /* hexadecimal value: \xHH */ - pos += 2; - } - } - if (pos >= ctx->len) - return ben_insufficient_ptr(ctx); - - s = malloc(len + 1); - if (s == NULL) - return ben_oom_ptr(ctx); - - pos = 0; - while (ctx->off < ctx->len) { - char c = ben_current_char(ctx); - assert(isprint(c)); - if (c == initial) - break; - assert(pos < len); - ctx->off++; - if (c != '\\') { - s[pos] = c; - pos++; - continue; /* Normal printable char, e.g. 'a' */ - } - /* Handle '\\' */ - - /* - * Note, we do assert because we have already verified in the - * previous loop that there is sufficient data. - */ - assert(ctx->off != ctx->len); - c = ben_current_char(ctx); - ctx->off++; - if (c == 'x') { - /* hexadecimal value: \xHH */ - char *end; - unsigned long x; - char buf[3]; - assert((ctx->off + 1) < ctx->len); - buf[0] = ctx->data[ctx->off + 0]; - buf[1] = ctx->data[ctx->off + 1]; - buf[2] = 0; - ctx->off += 2; - x = strtoul(buf, &end, 16); - if (*end != 0) - goto invalid; - assert(x < 256); - c = (char) x; - } - s[pos] = c; - pos++; - } - assert(pos == len); - if (ctx->off >= ctx->len) - return ben_insufficient_ptr(ctx); - ctx->off++; - - s[pos] = 0; /* the area must always be zero terminated! */ - - b = internal_blob(s, len); - if (b == NULL) { - free(s); - return ben_oom_ptr(ctx); - } - return b; - -invalid: - free(s); - return ben_invalid_ptr(ctx); -} - -static struct bencode *decode_printed(struct ben_decode_ctx *ctx) -{ - struct bencode *b; - - ctx->level++; - if (ctx->level > 256) - return ben_invalid_ptr(ctx); - - if (seek_char(ctx)) - return NULL; - - switch (ben_current_char(ctx)) { - case '\'': - case '"': - b = decode_printed_str(ctx); - break; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - b = decode_printed_int(ctx); - break; - case 'F': - case 'T': - b = decode_printed_bool(ctx); - break; - case '[': - b = decode_printed_list(ctx); - break; - case '{': - b = decode_printed_dict(ctx); - break; - default: - return ben_invalid_ptr(ctx); - } - ctx->level--; - return b; -} - -struct bencode *ben_decode_printed(const void *data, size_t len) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len}; - return decode_printed(&ctx); -} - -struct bencode *ben_decode_printed2(const void *data, size_t len, size_t *off, struct bencode_error *error) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len, .off = *off}; - struct bencode *b = decode_printed(&ctx); - *off = ctx.off; - if (error != NULL) { - assert((b != NULL) ^ (ctx.error != 0)); - error->error = ctx.error; - if (b != NULL) { - error->off = 0; - error->line = 0; - } else { - error->off = ctx.off; - error->line = ctx.line; - } - } - return b; -} - -static void free_dict(struct bencode_dict *d) -{ - size_t pos; - if (d->shared) - return; - for (pos = 0; pos < d->n; pos++) { - ben_free(d->nodes[pos].key); - ben_free(d->nodes[pos].value); - d->nodes[pos].key = NULL; - d->nodes[pos].value = NULL; - } - free(d->buckets); - free(d->nodes); -} - -static void free_list(struct bencode_list *list) -{ - size_t pos; - if (list->shared) - return; - for (pos = 0; pos < list->n; pos++) { - ben_free(list->values[pos]); - list->values[pos] = NULL; - } - free(list->values); -} - -int ben_put_char(struct ben_encode_ctx *ctx, char c) -{ - if (ctx->pos >= ctx->size) - return -1; - ctx->data[ctx->pos] = c; - ctx->pos++; - return 0; -} - -int ben_put_buffer(struct ben_encode_ctx *ctx, const void *buf, size_t len) -{ - if ((ctx->pos + len) > ctx->size) - return -1; - memcpy(ctx->data + ctx->pos, buf, len); - ctx->pos += len; - return 0; -} - -static int puthexchar(struct ben_encode_ctx *ctx, unsigned char hex) -{ - char buf[5]; - int len = snprintf(buf, sizeof buf, "\\x%.2x", hex); - assert(len == 4); - return ben_put_buffer(ctx, buf, len); -} - -static int putlonglong(struct ben_encode_ctx *ctx, long long ll) -{ - char buf[LONGLONGSIZE]; - int len = snprintf(buf, sizeof buf, "%lld", ll); - assert(len > 0); - return ben_put_buffer(ctx, buf, len); -} - -static int putunsignedlonglong(struct ben_encode_ctx *ctx, unsigned long long llu) -{ - char buf[LONGLONGSIZE]; - int len = snprintf(buf, sizeof buf, "%llu", llu); - assert(len > 0); - return ben_put_buffer(ctx, buf, len); -} - -static int putstr(struct ben_encode_ctx *ctx, char *s) -{ - return ben_put_buffer(ctx, s, strlen(s)); -} - -static int print(struct ben_encode_ctx *ctx, const struct bencode *b) -{ - const struct bencode_bool *boolean; - const struct bencode_int *integer; - const struct bencode_list *list; - const struct bencode_str *s; - size_t i; - size_t len; - struct bencode_keyvalue *pairs; - - switch (b->type) { - case BENCODE_BOOL: - boolean = ben_bool_const_cast(b); - return putstr(ctx, boolean->b ? "True" : "False"); - - case BENCODE_DICT: - if (ben_put_char(ctx, '{')) - return -1; - - pairs = ben_dict_ordered_items(b); - if (pairs == NULL) { - warn("No memory for dict serialization\n"); - return -1; - } - - len = ben_dict_len(b); - for (i = 0; i < len; i++) { - if (print(ctx, pairs[i].key)) - break; - if (putstr(ctx, ": ")) - break; - if (print(ctx, pairs[i].value)) - break; - if (i < (len - 1)) { - if (putstr(ctx, ", ")) - break; - } - } - free(pairs); - pairs = NULL; - if (i < len) - return -1; - - return ben_put_char(ctx, '}'); - - case BENCODE_INT: - integer = ben_int_const_cast(b); - - if (putlonglong(ctx, integer->ll)) - return -1; - - return 0; - - case BENCODE_LIST: - if (ben_put_char(ctx, '[')) - return -1; - list = ben_list_const_cast(b); - for (i = 0; i < list->n; i++) { - if (print(ctx, list->values[i])) - return -1; - if (i < (list->n - 1) && putstr(ctx, ", ")) - return -1; - } - return ben_put_char(ctx, ']'); - - case BENCODE_STR: - s = ben_str_const_cast(b); - if (ben_put_char(ctx, '\'')) - return -1; - for (i = 0; i < s->len; i++) { - if (!isprint(s->s[i])) { - if (puthexchar(ctx, s->s[i])) - return -1; - continue; - } - - switch (s->s[i]) { - case '\'': - case '\\': - /* Need escape character */ - if (ben_put_char(ctx, '\\')) - return -1; - default: - if (ben_put_char(ctx, s->s[i])) - return -1; - break; - } - } - return ben_put_char(ctx, '\''); - default: - die("serialization type %d not implemented\n", b->type); - } -} - -static size_t get_printed_size(const struct bencode *b) -{ - size_t pos; - const struct bencode_bool *boolean; - const struct bencode_dict *d; - const struct bencode_int *i; - const struct bencode_list *l; - const struct bencode_str *s; - size_t size = 0; - char buf[1]; - - switch (b->type) { - case BENCODE_BOOL: - boolean = ben_bool_const_cast(b); - return boolean->b ? 4 : 5; /* "True" and "False" */ - case BENCODE_DICT: - size++; /* "{" */ - d = ben_dict_const_cast(b); - for (pos = 0; pos < d->n; pos++) { - size += get_printed_size(d->nodes[pos].key); - size += 2; /* ": " */ - size += get_printed_size(d->nodes[pos].value); - if (pos < (d->n - 1)) - size += 2; /* ", " */ - } - size++; /* "}" */ - return size; - case BENCODE_INT: - i = ben_int_const_cast(b); - return snprintf(buf, 0, "%lld", i->ll); - case BENCODE_LIST: - size++; /* "[" */ - l = ben_list_const_cast(b); - for (pos = 0; pos < l->n; pos++) { - size += get_printed_size(l->values[pos]); - if (pos < (l->n - 1)) - size += 2; /* ", " */ - } - size++; /* "]" */ - return size; - case BENCODE_STR: - s = ben_str_const_cast(b); - size++; /* ' */ - for (pos = 0; pos < s->len; pos++) { - if (!isprint(s->s[pos])) { - size += 4; /* "\xDD" */ - continue; - } - switch (s->s[pos]) { - case '\'': - case '\\': - size += 2; /* escaped characters */ - break; - default: - size++; - break; - } - } - size++; /* ' */ - return size; - default: - die("Unknown type: %c\n", b->type); - } -} - -int ben_ctx_encode(struct ben_encode_ctx *ctx, const struct bencode *b) -{ - const struct bencode_bool *boolean; - const struct bencode_int *integer; - const struct bencode_list *list; - const struct bencode_str *s; - const struct bencode_user *u; - size_t i; - size_t len; - struct bencode_keyvalue *pairs; - - switch (b->type) { - case BENCODE_BOOL: - boolean = ben_bool_const_cast(b); - return putstr(ctx, boolean->b ? "b1" : "b0"); - - case BENCODE_DICT: - if (ben_put_char(ctx, 'd')) - return -1; - - pairs = ben_dict_ordered_items(b); - if (pairs == NULL) { - warn("No memory for dict serialization\n"); - return -1; - } - - len = ben_dict_len(b); - for (i = 0; i < len; i++) { - if (ben_ctx_encode(ctx, pairs[i].key)) - break; - if (ben_ctx_encode(ctx, pairs[i].value)) - break; - } - free(pairs); - pairs = NULL; - if (i < len) - return -1; - - return ben_put_char(ctx, 'e'); - - case BENCODE_INT: - if (ben_put_char(ctx, 'i')) - return -1; - integer = ben_int_const_cast(b); - if (putlonglong(ctx, integer->ll)) - return -1; - return ben_put_char(ctx, 'e'); - - case BENCODE_LIST: - if (ben_put_char(ctx, 'l')) - return -1; - - list = ben_list_const_cast(b); - for (i = 0; i < list->n; i++) { - if (ben_ctx_encode(ctx, list->values[i])) - return -1; - } - - return ben_put_char(ctx, 'e'); - - case BENCODE_STR: - s = ben_str_const_cast(b); - if (putunsignedlonglong(ctx, ((long long) s->len))) - return -1; - if (ben_put_char(ctx, ':')) - return -1; - return ben_put_buffer(ctx, s->s, s->len); - - case BENCODE_USER: - u = ben_user_const_cast(b); - return u->info->encode(ctx, b); - - default: - die("serialization type %d not implemented\n", b->type); - } -} - -static size_t get_size(const struct bencode *b) -{ - size_t pos; - const struct bencode_dict *d; - const struct bencode_int *i; - const struct bencode_list *l; - const struct bencode_str *s; - const struct bencode_user *u; - size_t size = 0; - char buf[1]; - - switch (b->type) { - case BENCODE_BOOL: - return 2; - case BENCODE_DICT: - d = ben_dict_const_cast(b); - for (pos = 0; pos < d->n; pos++) { - size += get_size(d->nodes[pos].key); - size += get_size(d->nodes[pos].value); - } - return size + 2; - case BENCODE_INT: - i = ben_int_const_cast(b); - return 2 + snprintf(buf, 0, "%lld", i->ll); - case BENCODE_LIST: - l = ben_list_const_cast(b); - for (pos = 0; pos < l->n; pos++) - size += get_size(l->values[pos]); - return size + 2; - case BENCODE_STR: - s = ben_str_const_cast(b); - return snprintf(buf, 0, "%zu", s->len) + 1 + s->len; - case BENCODE_USER: - u = ben_user_const_cast(b); - return u->info->get_size(b); - default: - die("Unknown type: %c\n", b->type); - } -} - -size_t ben_encoded_size(const struct bencode *b) -{ - return get_size(b); -} - -void *ben_encode(size_t *len, const struct bencode *b) -{ - size_t size = get_size(b); - void *data = malloc(size); - struct ben_encode_ctx ctx = {.data = data, .size = size}; - if (data == NULL) { - warn("No memory to encode\n"); - return NULL; - } - if (ben_ctx_encode(&ctx, b)) { - free(ctx.data); - return NULL; - } - assert(ctx.pos == size); - *len = ctx.pos; - return data; -} - -size_t ben_encode2(char *data, size_t maxlen, const struct bencode *b) -{ - struct ben_encode_ctx ctx = {.data = data, .size = maxlen, .pos = 0}; - if (ben_ctx_encode(&ctx, b)) - return -1; - return ctx.pos; -} - -void ben_free(struct bencode *b) -{ - struct bencode_str *s; - struct bencode_user *u; - size_t size; - if (b == NULL) - return; - switch (b->type) { - case BENCODE_BOOL: - break; - case BENCODE_DICT: - free_dict(ben_dict_cast(b)); - break; - case BENCODE_INT: - break; - case BENCODE_LIST: - free_list(ben_list_cast(b)); - break; - case BENCODE_STR: - s = ben_str_cast(b); - free(s->s); - break; - case BENCODE_USER: - u = ben_user_cast(b); - if (u->info->free) - u->info->free(b); - break; - default: - die("invalid type: %d\n", b->type); - } - - if (b->type == BENCODE_USER) - size = ((struct bencode_user *) b)->info->size; - else - size = type_size(b->type); - memset(b, -1, size); /* data poison */ - free(b); -} - -struct bencode *ben_blob(const void *data, size_t len) -{ - struct bencode_str *b = alloc(BENCODE_STR); - if (b == NULL) - return NULL; - /* Allocate one extra byte for zero termination for convenient use */ - b->s = malloc(len + 1); - if (b->s == NULL) { - free(b); - return NULL; - } - memcpy(b->s, data, len); - b->len = len; - b->s[len] = 0; - return (struct bencode *) b; -} - -struct bencode *ben_bool(int boolean) -{ - struct bencode_bool *b = alloc(BENCODE_BOOL); - if (b == NULL) - return NULL; - b->b = boolean ? 1 : 0; - return (struct bencode *) b; -} - -struct bencode *ben_dict(void) -{ - return alloc(BENCODE_DICT); -} - -struct bencode *ben_dict_get(const struct bencode *dict, const struct bencode *key) -{ - const struct bencode_dict *d = ben_dict_const_cast(dict); - long long hash = ben_hash(key); - size_t pos = hash_bucket_head(hash, d); - while (pos != -1) { - assert(pos < d->n); - if (d->nodes[pos].hash == hash && - ben_cmp(d->nodes[pos].key, key) == 0) - return d->nodes[pos].value; - pos = d->nodes[pos].next; - } - return NULL; -} - -/* - * Note, we do not re-allocate memory, so one may not call ben_free for these - * instances. These are only used to optimize speed. - */ -static void inplace_ben_str(struct bencode_str *b, const char *s, size_t len) -{ - b->type = BENCODE_STR; - b->len = len; - b->s = (char *) s; -} - -static void inplace_ben_int(struct bencode_int *i, long long ll) -{ - i->type = BENCODE_INT; - i->ll = ll; -} - -struct bencode *ben_dict_get_by_str(const struct bencode *dict, const char *key) -{ - struct bencode_str s; - inplace_ben_str(&s, key, strlen(key)); - return ben_dict_get(dict, (struct bencode *) &s); -} - -struct bencode *ben_dict_get_by_int(const struct bencode *dict, long long key) -{ - struct bencode_int i; - inplace_ben_int(&i, key); - return ben_dict_get(dict, (struct bencode *) &i); -} - -struct bencode_keyvalue *ben_dict_ordered_items(const struct bencode *b) -{ - struct bencode_keyvalue *pairs; - size_t i; - const struct bencode_dict *dict = ben_dict_const_cast(b); - if (dict == NULL) - return NULL; - pairs = malloc(dict->n * sizeof(pairs[0])); - if (pairs == NULL) - return NULL; - for (i = 0; i < dict->n; i++) { - pairs[i].key = dict->nodes[i].key; - pairs[i].value = dict->nodes[i].value; - } - qsort(pairs, dict->n, sizeof(pairs[0]), ben_cmp_qsort); - return pairs; -} - -static size_t dict_find_pos(struct bencode_dict *d, - const struct bencode *key, long long hash) -{ - size_t pos = hash_bucket_head(hash, d); - while (pos != -1) { - assert(pos < d->n); - if (d->nodes[pos].hash == hash && - ben_cmp(d->nodes[pos].key, key) == 0) - break; - pos = d->nodes[pos].next; - } - return pos; -} - -static void dict_unlink(struct bencode_dict *d, size_t bucket, size_t unlinkpos) -{ - size_t pos = d->buckets[bucket]; - size_t next; - size_t nextnext; - - assert(unlinkpos < d->n); - - if (pos == unlinkpos) { - next = d->nodes[unlinkpos].next; - assert(next < d->n || next == -1); - d->buckets[bucket] = next; - return; - } - while (pos != -1) { - assert(pos < d->n); - next = d->nodes[pos].next; - if (next == unlinkpos) { - nextnext = d->nodes[next].next; - assert(nextnext < d->n || nextnext == -1); - d->nodes[pos].next = nextnext; - return; - } - pos = next; - } - die("Key should have been found. Can not unlink position %zu.\n", unlinkpos); -} - -/* Remove node from the linked list, if found */ -static struct bencode *dict_pop(struct bencode_dict *d, - const struct bencode *key, long long hash) -{ - struct bencode *value; - size_t removebucket = hash_bucket(hash, d); - size_t tailpos = d->n - 1; - size_t tailhash = d->nodes[tailpos].hash; - size_t tailbucket = hash_bucket(tailhash, d); - size_t removepos; - - removepos = dict_find_pos(d, key, hash); - if (removepos == -1) - return NULL; - key = NULL; /* avoid using the pointer again, it may not be valid */ - - /* - * WARNING: complicated code follows. - * - * First, unlink the node to be removed and the tail node. - * We will actually later swap the positions of removed node and - * tail node inside the d->nodes array. We want to preserve - * d->nodes array in a state where positions from 0 to (d->n - 1) - * are always occupied with a valid node. This is done to make - * dictionary walk fast by simply walking positions 0 to (d->n - 1) - * in a for loop. - */ - dict_unlink(d, removebucket, removepos); - if (removepos != tailpos) - dict_unlink(d, tailbucket, tailpos); - - /* Then read the removed node and free its key */ - value = d->nodes[removepos].value; - ben_free(d->nodes[removepos].key); - - /* Then re-insert the unliked tail node in the place of removed node */ - d->nodes[removepos] = d->nodes[tailpos]; - memset(&d->nodes[tailpos], 0, sizeof d->nodes[tailpos]); /* poison */ - d->nodes[tailpos].next = ((size_t) -1) / 2; - - /* - * Then re-link the tail node to its bucket, unless the tail node - * was the one to be removed. - */ - if (removepos != tailpos) { - d->nodes[removepos].next = d->buckets[tailbucket]; - d->buckets[tailbucket] = removepos; - } - - d->n--; - - if (d->n <= (d->alloc / 4) && d->alloc >= 8) - resize_dict(d, d->alloc / 2); - - return value; -} - -struct bencode *ben_dict_pop(struct bencode *dict, const struct bencode *key) -{ - struct bencode_dict *d = ben_dict_cast(dict); - return dict_pop(d, key, ben_hash(key)); -} - -struct bencode *ben_dict_pop_by_str(struct bencode *dict, const char *key) -{ - struct bencode_str s; - inplace_ben_str(&s, key, strlen(key)); - return ben_dict_pop(dict, (struct bencode *) &s); -} - -struct bencode *ben_dict_pop_by_int(struct bencode *dict, long long key) -{ - struct bencode_int i; - inplace_ben_int(&i, key); - return ben_dict_pop(dict, (struct bencode *) &i); -} - -/* This can be used from the ben_dict_for_each() iterator */ -struct bencode *ben_dict_pop_current(struct bencode *dict, size_t *pos) -{ - struct bencode_dict *d = ben_dict_cast(dict); - struct bencode *value = ben_dict_pop(dict, d->nodes[*pos].key); - (*pos)--; - return value; -} - -int ben_dict_set(struct bencode *dict, struct bencode *key, struct bencode *value) -{ - struct bencode_dict *d = ben_dict_cast(dict); - long long hash = ben_hash(key); - size_t bucket; - size_t pos; - - assert(value != NULL); - - pos = hash_bucket_head(hash, d); - for (; pos != -1; pos = d->nodes[pos].next) { - assert(pos < d->n); - if (d->nodes[pos].hash != hash || ben_cmp(d->nodes[pos].key, key) != 0) - continue; - ben_free(d->nodes[pos].key); - ben_free(d->nodes[pos].value); - d->nodes[pos].key = key; - d->nodes[pos].value = value; - /* 'hash' and 'next' members stay the same */ - return 0; - } - - assert(d->n <= d->alloc); - if (d->n == d->alloc && resize_dict(d, -1)) - return -1; - - bucket = hash_bucket(hash, d); - pos = d->n; - d->nodes[pos] = (struct bencode_dict_node) {.hash = hash, - .key = key, - .value = value, - .next = d->buckets[bucket]}; - d->n++; - d->buckets[bucket] = pos; - return 0; -} - -int ben_dict_set_by_str(struct bencode *dict, const char *key, struct bencode *value) -{ - struct bencode *bkey = ben_str(key); - if (bkey == NULL) - return -1; - if (ben_dict_set(dict, bkey, value)) { - ben_free(bkey); - return -1; - } - return 0; -} - -int ben_dict_set_str_by_str(struct bencode *dict, const char *key, const char *value) -{ - struct bencode *bkey = ben_str(key); - struct bencode *bvalue = ben_str(value); - if (bkey == NULL || bvalue == NULL) { - ben_free(bkey); - ben_free(bvalue); - return -1; - } - if (ben_dict_set(dict, bkey, bvalue)) { - ben_free(bkey); - ben_free(bvalue); - return -1; - } - return 0; -} - -struct bencode *ben_int(long long ll) -{ - struct bencode_int *b = alloc(BENCODE_INT); - if (b == NULL) - return NULL; - b->ll = ll; - return (struct bencode *) b; -} - -struct bencode *ben_list(void) -{ - return alloc(BENCODE_LIST); -} - -int ben_list_append(struct bencode *list, struct bencode *b) -{ - struct bencode_list *l = ben_list_cast(list); - /* NULL pointer de-reference if the cast fails */ - assert(l->n <= l->alloc); - if (l->n == l->alloc && resize_list(l, -1)) - return -1; - assert(b != NULL); - l->values[l->n] = b; - l->n++; - return 0; -} - -int ben_list_append_str(struct bencode *list, const char *s) -{ - struct bencode *bs = ben_str(s); - if (bs == NULL) - return -1; - return ben_list_append(list, bs); -} - -int ben_list_append_int(struct bencode *list, long long ll) -{ - struct bencode *bll = ben_int(ll); - if (bll == NULL) - return -1; - return ben_list_append(list, bll); -} - -struct bencode *ben_list_pop(struct bencode *list, size_t pos) -{ - struct bencode_list *l = ben_list_cast(list); - struct bencode *value; - - assert(pos < l->n); - - value = ben_list_get(list, pos); - - for (; (pos + 1) < l->n; pos++) - l->values[pos] = l->values[pos + 1]; - - l->values[l->n - 1] = NULL; - l->n--; - return value; -} - -void ben_list_set(struct bencode *list, size_t i, struct bencode *b) -{ - struct bencode_list *l = ben_list_cast(list); - if (i >= l->n) - die("ben_list_set() out of bounds: %zu\n", i); - - ben_free(l->values[i]); - assert(b != NULL); - l->values[i] = b; -} - -char *ben_print(const struct bencode *b) -{ - size_t size = get_printed_size(b); - char *data = malloc(size + 1); - struct ben_encode_ctx ctx = {.data = data, .size = size, .pos = 0}; - if (data == NULL) { - warn("No memory to print\n"); - return NULL; - } - if (print(&ctx, b)) { - free(data); - return NULL; - } - assert(ctx.pos == size); - data[ctx.pos] = 0; - return data; -} - -struct bencode *ben_str(const char *s) -{ - return ben_blob(s, strlen(s)); -} - -const char *ben_strerror(int error) -{ - switch (error) { - case BEN_OK: - return "OK (no error)"; - case BEN_INVALID: - return "Invalid data"; - case BEN_INSUFFICIENT: - return "Insufficient amount of data (need more data)"; - case BEN_NO_MEMORY: - return "Out of memory"; - case BEN_MISMATCH: - return "A given structure did not match unpack format"; - default: - fprintf(stderr, "Unknown error code: %d\n", error); - return NULL; - } -} - -static int unpack_pointer(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - const char **str; - const struct bencode **ptr; - - ctx->off++; - - if (ctx->off >= ctx->len) - return insufficient(ctx); - - switch (ben_current_char(ctx)) { - case 's': /* %ps */ - ctx->off++; - if (b->type != BENCODE_STR) - return mismatch(ctx); - str = va_arg(*vl, const char **); - *str = ben_str_val(b); - return 0; - - case 'b': /* %pb */ - ctx->off++; - ptr = va_arg(*vl, const struct bencode **); - *ptr = b; - return 0; - - default: - return invalid(ctx); - } -} - -static int unpack_value(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - long long val; - long long *ll; - long *l; - int *i; - unsigned long long *ull; - unsigned long *ul; - unsigned int *ui; - int longflag = 0; - - ctx->off++; - - while (ctx->off < ctx->len) { - switch (ben_current_char(ctx)) { - case 'l': - ctx->off++; - longflag++; - break; - case 'L': - case 'q': - ctx->off++; - longflag = 2; - break; - - case 'p': - return unpack_pointer(b, ctx, vl); - - /* signed */ - case 'd': - ctx->off++; - if (b->type != BENCODE_INT) - return mismatch(ctx); - val = ben_int_val(b); - switch (longflag) { - case 0: - i = va_arg(*vl, int *); - *i = val; - /* Test that no information was lost in conversion */ - if ((long long) *i != val) - return mismatch(ctx); - break; - case 1: - l = va_arg(*vl, long *); - *l = val; - if ((long long) *l != val) - return mismatch(ctx); - break; - case 2: - ll = va_arg(*vl, long long *); - *ll = val; - break; - } - return 0; - - /* unsigned */ - case 'u': - ctx->off++; - if (b->type != BENCODE_INT) - return mismatch(ctx); - val = ben_int_val(b); - if (val < 0) - return mismatch(ctx); - switch (longflag) { - case 0: - ui = va_arg(*vl, unsigned int *); - *ui = val; - if ((long long) *ui != val) - return mismatch(ctx); - break; - case 1: - ul = va_arg(*vl, unsigned long *); - *ul = val; - if ((long long) *ul != val) - return mismatch(ctx); - break; - case 2: - ull = va_arg(*vl, unsigned long long *); - *ull = val; - break; - } - return 0; - - default: - return invalid(ctx); - } - } - return insufficient(ctx); -} - -static int unpack_dict(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - struct bencode *key = NULL; - const struct bencode *val; - - if (b->type != BENCODE_DICT) - return mismatch(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - return -1; - - if (ben_current_char(ctx) == '}') { - ctx->off++; - break; - } - switch (ben_current_char(ctx)) { - case '\'': - case '"': - key = decode_printed_str(ctx); - break; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - key = decode_printed_int(ctx); - break; - default: - return invalid(ctx); - } - if (key == NULL) - return -1; - val = ben_dict_get(b, key); - ben_free(key); - if (val == NULL) - return mismatch(ctx); - - if (seek_char(ctx)) - return -1; - if (ben_current_char(ctx) != ':') - return invalid(ctx); - ctx->off++; - - if (unpack(val, ctx, vl)) - return -1; - - if (seek_char(ctx)) - return -1; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != '}') - return invalid(ctx); - } - return 0; -} - -static int unpack_list(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - const struct bencode_list *list; - size_t i = 0; - - if (b->type != BENCODE_LIST) - return mismatch(ctx); - list = ben_list_const_cast(b); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - return -1; - - if (ben_current_char(ctx) == ']') { - ctx->off++; - break; - } - if (i >= list->n) - return mismatch(ctx); - if (unpack(list->values[i], ctx, vl)) - return -1; - i++; - - if (seek_char(ctx)) - return -1; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != ']') - return invalid(ctx); - } - if (i != list->n) - return mismatch(ctx); - return 0; -} - -static int unpack(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - if (seek_char(ctx)) - return insufficient(ctx); - - switch (ben_current_char(ctx)) { - case '{': - return unpack_dict(b, ctx, vl); - case '[': - return unpack_list(b, ctx, vl); - case '%': - return unpack_value(b, ctx, vl); - default: - break; - } - return -1; -} - -static int unpack_all(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - if (unpack(b, ctx, vl)) - return -1; - /* check for left over characters */ - seek_char(ctx); - ctx->error = 0; - if (ctx->off < ctx->len) - return invalid(ctx); - return 0; -} - -int ben_unpack(const struct bencode *b, const char *fmt, ...) -{ - struct ben_decode_ctx ctx = {.data = fmt, .len = strlen(fmt)}; - int ret; - va_list vl; - va_start(vl, fmt); - ret = unpack_all(b, &ctx, &vl); - va_end(vl); - return ret; -} - -int ben_unpack2(const struct bencode *b, size_t *off, struct bencode_error *error, const char *fmt, ...) -{ - struct ben_decode_ctx ctx = {.data = fmt, .len = strlen(fmt)}; - int ret; - va_list vl; - va_start(vl, fmt); - ret = unpack_all(b, &ctx, &vl); - va_end(vl); - - *off = ctx.off; - if (error != NULL) { - assert((ret == 0) ^ (ctx.error != 0)); - error->error = ctx.error; - if (ret != 0) { - error->off = 0; - error->line = 0; - } else { - error->off = ctx.off; - error->line = ctx.line; - } - } - return 0; -} - -static struct bencode *pack_pointer(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *b = NULL; - - ctx->off++; - - if (ctx->off >= ctx->len) - return ben_insufficient_ptr(ctx); - - switch (ben_current_char(ctx)) { - case 'b': /* %pb */ - ctx->off++; - b = va_arg(*vl, struct bencode *); - break; - default: - return ben_invalid_ptr(ctx); - } - return b; -} - -static struct bencode *pack_value(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *b = NULL; - unsigned long long ull; - long long val; - int longflag = 0; - - ctx->off++; - - while (ctx->off < ctx->len) { - switch (ben_current_char(ctx)) { - case 'l': - ctx->off++; - longflag++; - break; - case 'L': - case 'q': - ctx->off++; - longflag = 2; - break; - - case 's': - ctx->off++; - b = ben_str(va_arg(*vl, const char *)); - if (b == NULL) - return ben_oom_ptr(ctx); - break; - - case 'p': - b = pack_pointer(ctx, vl); - break; - - /* signed */ - case 'd': - ctx->off++; - switch (longflag) { - case 0: - val = va_arg(*vl, int); - break; - case 1: - val = va_arg(*vl, long); - break; - case 2: - val = va_arg(*vl, long long); - break; - default: - return ben_invalid_ptr(ctx); - } - b = ben_int(val); - if (b == NULL) - return ben_oom_ptr(ctx); - break; - - /* unsigned */ - case 'u': - ctx->off++; - switch (longflag) { - case 0: - val = va_arg(*vl, unsigned int); - break; - case 1: - val = va_arg(*vl, unsigned long); - break; - case 2: - ull = va_arg(*vl, unsigned long long); - /* Check that no information was lost */ - val = ull; - if ((long long) ull != val) - return ben_invalid_ptr(ctx); - break; - default: - return ben_invalid_ptr(ctx); - } - b = ben_int(val); - if (b == NULL) - return ben_oom_ptr(ctx); - break; - - default: - return ben_invalid_ptr(ctx); - } - if (b) - return b; - } - return ben_insufficient_ptr(ctx); -} - -static struct bencode *pack_dict(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *d = ben_dict(); - struct bencode *key = NULL; - struct bencode *value = NULL; - - if (d == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - - if (ben_current_char(ctx) == '}') { - ctx->off++; - break; - } - key = pack(ctx, vl); - if (key == NULL) - goto nullpath; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) != ':') - goto invalidpath; - ctx->off++; - - value = pack(ctx, vl); - if (value == NULL) - goto nullpath; - - if (ben_dict_set(d, key, value)) { - ben_free(key); - ben_free(value); - ben_free(d); - return ben_oom_ptr(ctx); - } - key = NULL; - value = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != '}') - goto invalidpath; - } - return d; - -nullpath: - ben_free(d); - ben_free(key); - ben_free(value); - return NULL; - -invalidpath: - ben_free(d); - ben_free(key); - ben_free(value); - return ben_invalid_ptr(ctx); -} - -static struct bencode *pack_list(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *l = ben_list(); - struct bencode *val = NULL; - - if (l == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - - if (ben_current_char(ctx) == ']') { - ctx->off++; - break; - } - val = pack(ctx, vl); - if (val == NULL) - goto nullpath; - - if (ben_list_append(l, val)) { - ben_free(val); - ben_free(l); - return ben_oom_ptr(ctx); - } - val = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != ']') { - ben_free(l); - return ben_invalid_ptr(ctx); - } - } - - return l; - -nullpath: - ben_free(l); - ben_free(val); - return NULL; -} - -static struct bencode *pack(struct ben_decode_ctx *ctx, va_list *vl) -{ - if (seek_char(ctx)) - return ben_insufficient_ptr(ctx); - - switch (ben_current_char(ctx)) { - case '\'': - case '"': - return decode_printed_str(ctx); - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return decode_printed_int(ctx); - case 'F': - case 'T': - return decode_printed_bool(ctx); - case '{': - return pack_dict(ctx, vl); - case '[': - return pack_list(ctx, vl); - case '%': - return pack_value(ctx, vl); - default: - return ben_invalid_ptr(ctx); - } - return NULL; -} - -struct bencode *ben_pack(const char *fmt, ...) -{ - struct ben_decode_ctx ctx = {.data = fmt, .len = strlen(fmt)}; - struct bencode *b; - va_list vl; - va_start(vl, fmt); - b = pack(&ctx, &vl); - va_end(vl); - - /* check for left over characters */ - seek_char(&ctx); - if (ctx.off < ctx.len) { - ben_free(b); - return NULL; - } - return b; -} diff --git a/libs/libblade/src/blade.c b/libs/libblade/src/blade.c deleted file mode 100644 index 64d51269f8..0000000000 --- a/libs/libblade/src/blade.c +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -KS_DECLARE(ks_status_t) blade_init(void) -{ - ks_status_t ret = ks_init(); - - if (ret == KS_STATUS_SUCCESS && mg_init_library(0xFFu) == 0) ret = KS_STATUS_FAIL; - - return ret; -} - -KS_DECLARE(ks_status_t) blade_shutdown(void) -{ - ks_status_t ret = ks_shutdown(); - mg_exit_library(); -#ifdef _WINDOWS_ - _CrtDumpMemoryLeaks(); -#endif - return ret; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_channel.c b/libs/libblade/src/blade_channel.c deleted file mode 100644 index c976563803..0000000000 --- a/libs/libblade/src/blade_channel.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_channel_s { - const char *name; - blade_channel_flags_t flags; - ks_rwl_t *lock; - ks_hash_t *authorizations; -}; - - -static void blade_channel_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_channel_t *bc = (blade_channel_t *)ptr; - - ks_assert(bc); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (bc->name) ks_pool_free(&bc->name); - if (bc->lock) ks_rwl_destroy(&bc->lock); - if (bc->authorizations) ks_hash_destroy(&bc->authorizations); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_channel_create(blade_channel_t **bcP, ks_pool_t *pool, const char *name, blade_channel_flags_t flags) -{ - blade_channel_t *bc = NULL; - - ks_assert(bcP); - ks_assert(pool); - ks_assert(name); - - bc = ks_pool_alloc(pool, sizeof(blade_channel_t)); - bc->name = ks_pstrdup(pool, name); - bc->flags = flags; - - ks_rwl_create(&bc->lock, pool); - ks_assert(bc->lock); - - ks_hash_create(&bc->authorizations, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bc->authorizations); - - ks_pool_set_cleanup(bc, NULL, blade_channel_cleanup); - - *bcP = bc; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_channel_destroy(blade_channel_t **bcP) -{ - ks_assert(bcP); - ks_assert(*bcP); - - ks_pool_free(bcP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_channel_name_get(blade_channel_t *bc) -{ - ks_assert(bc); - return bc->name; -} - -KS_DECLARE(blade_channel_flags_t) blade_channel_flags_get(blade_channel_t *bc) -{ - ks_assert(bc); - return bc->flags; -} - -KS_DECLARE(ks_status_t) blade_channel_read_lock(blade_channel_t *bc) -{ - ks_assert(bc); - return ks_rwl_read_lock(bc->lock); -} - -KS_DECLARE(ks_status_t) blade_channel_read_unlock(blade_channel_t *bc) -{ - ks_assert(bc); - return ks_rwl_read_unlock(bc->lock); -} - -KS_DECLARE(ks_status_t) blade_channel_write_lock(blade_channel_t *bc) -{ - ks_assert(bc); - return ks_rwl_write_lock(bc->lock); -} - -KS_DECLARE(ks_status_t) blade_channel_write_unlock(blade_channel_t *bc) -{ - ks_assert(bc); - return ks_rwl_write_unlock(bc->lock); -} - -KS_DECLARE(ks_bool_t) blade_channel_authorization_verify(blade_channel_t *bc, const char *target) -{ - ks_bool_t authorized = KS_FALSE; - - ks_assert(bc); - ks_assert(target); - - authorized = (ks_bool_t)(uintptr_t)ks_hash_search(bc->authorizations, (void *)target, KS_READLOCKED); - ks_hash_read_unlock(bc->authorizations); - - return authorized; -} - -KS_DECLARE(ks_status_t) blade_channel_authorization_add(blade_channel_t *bc, const char *target) -{ - ks_assert(bc); - ks_assert(target); - - ks_hash_insert(bc->authorizations, (void *)ks_pstrdup(ks_pool_get(bc), target), (void *)KS_TRUE); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_bool_t) blade_channel_authorization_remove(blade_channel_t *bc, const char *target) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(bc); - ks_assert(target); - - if (ks_hash_remove(bc->authorizations, (void *)target)) { - ret = KS_TRUE; - } - - return ret; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_connection.c b/libs/libblade/src/blade_connection.c deleted file mode 100644 index 9ecff88f21..0000000000 --- a/libs/libblade/src/blade_connection.c +++ /dev/null @@ -1,481 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_connection_s { - blade_handle_t *handle; - - void *transport_data; - blade_transport_callbacks_t *transport_callbacks; - - blade_connection_direction_t direction; - volatile blade_connection_state_t state; - - ks_cond_t *cond; - - const char *id; - ks_rwl_t *lock; - - ks_q_t *sending; - - const char *session; -}; - -void *blade_connection_state_thread(ks_thread_t *thread, void *data); -ks_status_t blade_connection_onstate_startup(blade_connection_t *bc); -ks_status_t blade_connection_onstate_shutdown(blade_connection_t *bc); -ks_status_t blade_connection_onstate_run(blade_connection_t *bc); - - -static void blade_connection_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_connection_t *bc = (blade_connection_t *)ptr; - - ks_assert(bc); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - blade_connection_shutdown(bc); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_connection_create(blade_connection_t **bcP, blade_handle_t *bh) -{ - blade_connection_t *bc = NULL; - ks_pool_t *pool = NULL; - uuid_t id; - - ks_assert(bcP); - ks_assert(bh); - - ks_pool_open(&pool); - ks_assert(pool); - - bc = ks_pool_alloc(pool, sizeof(blade_connection_t)); - bc->handle = bh; - - ks_cond_create(&bc->cond, pool); - ks_assert(bc->cond); - - ks_uuid(&id); - bc->id = ks_uuid_str(pool, &id); - ks_assert(bc->id); - - ks_rwl_create(&bc->lock, pool); - ks_assert(bc->lock); - - ks_q_create(&bc->sending, pool, 0); - ks_assert(bc->sending); - - ks_pool_set_cleanup(bc, NULL, blade_connection_cleanup); - - ks_log(KS_LOG_DEBUG, "Created\n"); - - *bcP = bc; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_connection_destroy(blade_connection_t **bcP) -{ - blade_connection_t *bc = NULL; - ks_pool_t *pool = NULL; - - ks_assert(bcP); - ks_assert(*bcP); - - bc = *bcP; - *bcP = NULL; - - pool = ks_pool_get(bc); - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_connection_startup(blade_connection_t *bc, blade_connection_direction_t direction) -{ - blade_handle_t *bh = NULL; - - ks_assert(bc); - - bh = blade_connection_handle_get(bc); - - bc->direction = direction; - blade_connection_state_set(bc, BLADE_CONNECTION_STATE_NONE); - - if (ks_thread_pool_add_job(blade_handle_tpool_get(bh), blade_connection_state_thread, bc) != KS_STATUS_SUCCESS) { - // @todo error logging - return KS_STATUS_FAIL; - } - - ks_log(KS_LOG_DEBUG, "Started\n"); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_connection_shutdown(blade_connection_t *bc) -{ - cJSON *json = NULL; - - ks_assert(bc); - - blade_connectionmgr_connection_remove(blade_handle_connectionmgr_get(bc->handle), bc); - - while (ks_q_trypop(bc->sending, (void **)&json) == KS_STATUS_SUCCESS && json) cJSON_Delete(json); - - ks_log(KS_LOG_DEBUG, "Stopped\n"); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_connection_handle_get(blade_connection_t *bc) -{ - ks_assert(bc); - - return bc->handle; -} - -KS_DECLARE(const char *) blade_connection_id_get(blade_connection_t *bc) -{ - ks_assert(bc); - - return bc->id; -} - -KS_DECLARE(ks_status_t) blade_connection_read_lock(blade_connection_t *bc, ks_bool_t block) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(bc); - - if (block) ret = ks_rwl_read_lock(bc->lock); - else ret = ks_rwl_try_read_lock(bc->lock); - return ret; -} - -KS_DECLARE(ks_status_t) blade_connection_read_unlock(blade_connection_t *bc) -{ - ks_assert(bc); - - return ks_rwl_read_unlock(bc->lock); -} - -KS_DECLARE(ks_status_t) blade_connection_write_lock(blade_connection_t *bc, ks_bool_t block) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(bc); - - if (block) ret = ks_rwl_write_lock(bc->lock); - else ret = ks_rwl_try_write_lock(bc->lock); - return ret; -} - -KS_DECLARE(ks_status_t) blade_connection_write_unlock(blade_connection_t *bc) -{ - ks_assert(bc); - - return ks_rwl_write_unlock(bc->lock); -} - - -KS_DECLARE(void *) blade_connection_transport_get(blade_connection_t *bc) -{ - ks_assert(bc); - - return bc->transport_data; -} - -KS_DECLARE(void) blade_connection_transport_set(blade_connection_t *bc, void *transport_data, blade_transport_callbacks_t *transport_callbacks) -{ - ks_assert(bc); - ks_assert(transport_data); - ks_assert(transport_callbacks); - - bc->transport_data = transport_data; - bc->transport_callbacks = transport_callbacks; -} - -blade_transport_state_callback_t blade_connection_state_callback_lookup(blade_connection_t *bc, blade_connection_state_t state) -{ - blade_transport_state_callback_t callback = NULL; - - ks_assert(bc); - - switch (state) { - case BLADE_CONNECTION_STATE_SHUTDOWN: - if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_shutdown_inbound; - else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_shutdown_outbound; - break; - case BLADE_CONNECTION_STATE_STARTUP: - if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_startup_inbound; - else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_startup_outbound; - break; - case BLADE_CONNECTION_STATE_RUN: - if (bc->direction == BLADE_CONNECTION_DIRECTION_INBOUND) callback = bc->transport_callbacks->onstate_run_inbound; - else if(bc->direction == BLADE_CONNECTION_DIRECTION_OUTBOUND) callback = bc->transport_callbacks->onstate_run_outbound; - break; - default: break; - } - - return callback; -} - -KS_DECLARE(void) blade_connection_state_set(blade_connection_t *bc, blade_connection_state_t state) -{ - blade_transport_state_callback_t callback = NULL; - blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS; - - ks_assert(bc); - - ks_cond_lock(bc->cond); - - callback = blade_connection_state_callback_lookup(bc, state); - - if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_PRE); - - bc->state = state; - - ks_cond_unlock(bc->cond); - - if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc); - - ks_cond_try_signal(bc->cond); -} - -KS_DECLARE(blade_connection_state_t) blade_connection_state_get(blade_connection_t *bc) -{ - ks_assert(bc); - return bc->state; -} - -KS_DECLARE(void) blade_connection_disconnect(blade_connection_t *bc) -{ - ks_assert(bc); - - if (bc->state != BLADE_CONNECTION_STATE_SHUTDOWN && bc->state != BLADE_CONNECTION_STATE_CLEANUP) { - ks_log(KS_LOG_DEBUG, "Connection (%s) disconnecting\n", bc->id); - blade_connection_state_set(bc, BLADE_CONNECTION_STATE_SHUTDOWN); - } -} - -KS_DECLARE(ks_status_t) blade_connection_sending_push(blade_connection_t *bc, cJSON *json) -{ - cJSON *json_copy = NULL; - - ks_assert(bc); - ks_assert(json); - - json_copy = cJSON_Duplicate(json, 1); - return ks_q_push(bc->sending, json_copy); -} - -KS_DECLARE(ks_status_t) blade_connection_sending_pop(blade_connection_t *bc, cJSON **json) -{ - ks_assert(bc); - ks_assert(json); - - return ks_q_trypop(bc->sending, (void **)json); -} - -KS_DECLARE(const char *) blade_connection_session_get(blade_connection_t *bc) -{ - ks_assert(bc); - - return bc->session; -} - -KS_DECLARE(void) blade_connection_session_set(blade_connection_t *bc, const char *id) -{ - ks_assert(bc); - - if (bc->session) ks_pool_free(&bc->session); - bc->session = ks_pstrdup(ks_pool_get(bc), id); -} - -void *blade_connection_state_thread(ks_thread_t *thread, void *data) -{ - blade_connection_t *bc = NULL; - blade_connection_state_t state; - ks_bool_t shutdown = KS_FALSE; - - ks_assert(thread); - ks_assert(data); - - bc = (blade_connection_t *)data; - - ks_cond_lock(bc->cond); - while (!shutdown) { - // Entering the call below, the mutex is expected to be locked and will be unlocked by the call - ks_cond_timedwait(bc->cond, 100); - // Leaving the call above, the mutex will be locked after being signalled, timing out, or woken up for any reason - - state = bc->state; - - switch (state) { - case BLADE_CONNECTION_STATE_SHUTDOWN: - blade_connection_onstate_shutdown(bc); - shutdown = KS_TRUE; - break; - case BLADE_CONNECTION_STATE_STARTUP: - blade_connection_onstate_startup(bc); - break; - case BLADE_CONNECTION_STATE_RUN: - blade_connection_onstate_run(bc); - break; - default: break; - } - } - ks_cond_unlock(bc->cond); - - blade_connection_destroy(&bc); - - return NULL; -} - -ks_status_t blade_connection_onstate_startup(blade_connection_t *bc) -{ - blade_transport_state_callback_t callback = NULL; - blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS; - - ks_assert(bc); - - callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_STARTUP); - if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST); - - if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc); - else if (hook == BLADE_CONNECTION_STATE_HOOK_SUCCESS) { - // @todo this is adding a second lock, since we keep it locked in the callback to allow finishing, we don't want get locking here... - // or just unlock twice... - blade_session_t *bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bc->handle), bc->session); - ks_assert(bs); // should not happen because bs should still be locked - - blade_session_connection_set(bs, bc->id); - - blade_connection_state_set(bc, BLADE_CONNECTION_STATE_RUN); - blade_session_state_set(bs, BLADE_SESSION_STATE_STARTUP); // if reconnecting, we go from RUN back to STARTUP for the purpose of the reconnect which will return to RUN - - blade_session_read_unlock(bs); // unlock the session we locked obtaining it above - blade_session_read_unlock(bs); // unlock the session we expect to be locked during the callback to ensure we can finish attaching - } - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_connection_onstate_shutdown(blade_connection_t *bc) -{ - blade_transport_state_callback_t callback = NULL; - - ks_assert(bc); - - callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_SHUTDOWN); - if (callback) callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST); - - if (bc->session) { - blade_session_t *bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bc->handle), bc->session); - ks_assert(bs); - - blade_session_connection_set(bs, NULL); - blade_session_read_unlock(bs); - // keep bc->session for later in case something triggers a reconnect later and needs the old session id for a hint - } - - blade_connection_state_set(bc, BLADE_CONNECTION_STATE_CLEANUP); - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_connection_onstate_run(blade_connection_t *bc) -{ - blade_transport_state_callback_t callback = NULL; - blade_connection_state_hook_t hook = BLADE_CONNECTION_STATE_HOOK_SUCCESS; - cJSON *json = NULL; - blade_session_t *bs = NULL; - ks_bool_t done = KS_FALSE; - - ks_assert(bc); - - while (blade_connection_sending_pop(bc, &json) == KS_STATUS_SUCCESS && json) { - ks_status_t ret = bc->transport_callbacks->onsend(bc, json); - cJSON_Delete(json); - - if (ret != KS_STATUS_SUCCESS) { - blade_connection_disconnect(bc); - break; - } - } - - while (!done) { - if (bc->transport_callbacks->onreceive(bc, &json) != KS_STATUS_SUCCESS) { - blade_connection_disconnect(bc); - break; - } - - if (!(done = (json == NULL))) { - if (!bs) { - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bc->handle), bc->session); - ks_assert(bs); - } - blade_session_receiving_push(bs, json); - cJSON_Delete(json); - json = NULL; - } - } - if (bs) blade_session_read_unlock(bs); - - callback = blade_connection_state_callback_lookup(bc, BLADE_CONNECTION_STATE_RUN); - if (callback) hook = callback(bc, BLADE_CONNECTION_STATE_CONDITION_POST); - - if (hook == BLADE_CONNECTION_STATE_HOOK_DISCONNECT) blade_connection_disconnect(bc); - - return KS_STATUS_SUCCESS; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_connectionmgr.c b/libs/libblade/src/blade_connectionmgr.c deleted file mode 100644 index 4d4445be91..0000000000 --- a/libs/libblade/src/blade_connectionmgr.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_connectionmgr_s { - blade_handle_t *handle; - - ks_hash_t *connections; // id, blade_connection_t* -}; - - -static void blade_connectionmgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_connectionmgr_t *bcmgr = (blade_connectionmgr_t *)ptr; - - //ks_assert(bcmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_connectionmgr_create(blade_connectionmgr_t **bcmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_connectionmgr_t *bcmgr = NULL; - - ks_assert(bcmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - bcmgr = ks_pool_alloc(pool, sizeof(blade_connectionmgr_t)); - bcmgr->handle = bh; - - ks_hash_create(&bcmgr->connections, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bcmgr->connections); - - ks_pool_set_cleanup(bcmgr, NULL, blade_connectionmgr_cleanup); - - *bcmgrP = bcmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_connectionmgr_destroy(blade_connectionmgr_t **bcmgrP) -{ - blade_connectionmgr_t *bcmgr = NULL; - ks_pool_t *pool; - - ks_assert(bcmgrP); - ks_assert(*bcmgrP); - - bcmgr = *bcmgrP; - *bcmgrP = NULL; - - pool = ks_pool_get(bcmgr); - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_connectionmgr_handle_get(blade_connectionmgr_t *bcmgr) -{ - ks_assert(bcmgr); - return bcmgr->handle; -} - -KS_DECLARE(ks_status_t) blade_connectionmgr_shutdown(blade_connectionmgr_t *bcmgr) -{ - ks_hash_iterator_t *it = NULL; - - ks_assert(bcmgr); - - ks_hash_read_lock(bcmgr->connections); - for (it = ks_hash_first(bcmgr->connections, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - blade_connection_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - blade_connection_disconnect(value); - } - ks_hash_read_unlock(bcmgr->connections); - while (ks_hash_count(bcmgr->connections) > 0) ks_sleep_ms(100); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_connection_t *) blade_connectionmgr_connection_lookup(blade_connectionmgr_t *bcmgr, const char *id) -{ - blade_connection_t *bc = NULL; - - ks_assert(bcmgr); - ks_assert(id); - - bc = ks_hash_search(bcmgr->connections, (void *)id, KS_READLOCKED); - if (bc) blade_connection_read_lock(bc, KS_TRUE); - ks_hash_read_unlock(bcmgr->connections); - - return bc; -} - -KS_DECLARE(ks_status_t) blade_connectionmgr_connection_add(blade_connectionmgr_t *bcmgr, blade_connection_t *bc) -{ - char *key = NULL; - - ks_assert(bcmgr); - ks_assert(bc); - - key = ks_pstrdup(ks_pool_get(bcmgr), blade_connection_id_get(bc)); - ks_hash_insert(bcmgr->connections, (void *)key, bc); - - ks_log(KS_LOG_DEBUG, "Connection Added: %s\n", key); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_connectionmgr_connection_remove(blade_connectionmgr_t *bcmgr, blade_connection_t *bc) -{ - const char *id = NULL; - - ks_assert(bcmgr); - ks_assert(bc); - - blade_connection_write_lock(bc, KS_TRUE); - - id = blade_connection_id_get(bc); - ks_hash_remove(bcmgr->connections, (void *)id); - - blade_connection_write_unlock(bc); - - ks_log(KS_LOG_DEBUG, "Connection Removed: %s\n", id); - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_identity.c b/libs/libblade/src/blade_identity.c deleted file mode 100644 index 582f047a3b..0000000000 --- a/libs/libblade/src/blade_identity.c +++ /dev/null @@ -1,357 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_identity_s { - const char *uri; - - const char *components; - - const char *scheme; - const char *user; - const char *host; - const char *port; - ks_port_t portnum; - const char *path; - ks_hash_t *parameters; -}; - -// @todo missed a structure to use cleanup callbacks -static void blade_identity_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_identity_t *bi = (blade_identity_t *)ptr; - - ks_assert(bi); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (bi->uri) ks_pool_free(&bi->uri); - if (bi->components) ks_pool_free(&bi->components); - if (bi->parameters) ks_hash_destroy(&bi->parameters); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_identity_create(blade_identity_t **biP, ks_pool_t *pool) -{ - blade_identity_t *bi = NULL; - - ks_assert(biP); - ks_assert(pool); - - bi = ks_pool_alloc(pool, sizeof(blade_identity_t)); - - ks_pool_set_cleanup(bi, NULL, blade_identity_cleanup); - - *biP = bi; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_identity_destroy(blade_identity_t **biP) -{ - ks_assert(biP); - ks_assert(*biP); - - ks_pool_free(biP); - - return KS_STATUS_SUCCESS; -} - -void blade_identity_reset(blade_identity_t *bi) -{ - ks_assert(bi); - - bi->scheme = NULL; - bi->user = NULL; - bi->host = NULL; - bi->port = NULL; - bi->portnum = 0; - bi->path = NULL; - - if (bi->uri) { - ks_pool_free(&bi->uri); - ks_pool_free(&bi->components); - } - if (bi->parameters) ks_hash_destroy(&bi->parameters); -} - -KS_DECLARE(ks_status_t) blade_identity_parse(blade_identity_t *bi, const char *uri) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - char *tmp = NULL; - char *tmp2 = NULL; - char terminator = '\0'; - ks_pool_t *pool = NULL; - - ks_assert(bi); - ks_assert(uri); - - ks_log(KS_LOG_DEBUG, "Parsing URI: %s\n", uri); - - pool = ks_pool_get(bi); - - blade_identity_reset(bi); - - bi->uri = ks_pstrdup(pool, uri); - bi->components = tmp = ks_pstrdup(pool, uri); - - // Supported components with pseudo regex - // [user@] [:port] [/path] [;param1=value1] [;param2=value2] - - // scheme is mandatory to simplify the parser for now, it must start with mandatory: : - bi->scheme = tmp; - if (!(tmp = strchr(tmp, ':'))) { - ret = KS_STATUS_FAIL; - goto done; - } - // if found, null terminate scheme portion - *tmp++ = '\0'; - // may have trailing '/' characters which are optional, this is not perfect it should probably only match a count of 0 or 2 explicitly - while (*tmp && *tmp == '/') ++tmp; - // must have more data to define at least a host - if (!*tmp) { - ret = KS_STATUS_FAIL; - goto done; - } - - if (!(*bi->scheme)) { - ret = KS_STATUS_FAIL; - goto done; - } - - // next component may be the user or the host, so it may start with optional: @ - // or it may skip to the host, which may be terminated by an optional port, optional path, optional parameters, or the end of the uri - // which means checking if an '@' appears before the next ':' for port, '/' for path, or ';' for parameters, if @ appears at all then it appears before end of the uri - // @todo need to account for host being encapsulated by '[' and ']' as in the case of an IPV6 host to distinguish from the port, but for simplicity allow any - // host to be encapsulated in which case if the string starts with a '[' here, then it MUST be the host and it MUST be terminated with the matching ']' rather than other - // optional component terminators - if (!(tmp2 = strpbrk(tmp, "@:/;"))) { - // none of the terminators are found, treat the remaining string as a host - bi->host = tmp; - goto done; - } - - // grab the terminator and null terminate for the next component - terminator = *tmp2; - *tmp2++ = '\0'; - - if (terminator == '@') { - // if the terminator was an '@', then we have a user component before the host - bi->user = tmp; - - tmp = tmp2; - - if (!(*bi->user)) { - ret = KS_STATUS_FAIL; - goto done; - } - - // repeat the same as above, except without looking for '@', to find only the end of the host, parsing to the same point as above if user was not found - if (!(tmp2 = strpbrk(tmp, ":/;"))) { - // none of the terminators are found, treat the remaining string as a host - bi->host = tmp; - goto done; - } - - // grab the terminator and null terminate for the next component - terminator = *tmp2; - *tmp2++ = '\0'; - } - - // at this point the user portion has been parsed if it exists, the host portion has been terminated, and there is still data remaining to parse - // @todo need to account for host being encapsulated by '[' and ']' as in the case of an IPV6 host to distinguish from the port, but for simplicity allow any - // host to be encapsulated in which case the terminator MUST be the closing ']' - bi->host = tmp; - tmp = tmp2; - - if (!(*bi->host)) { - ret = KS_STATUS_FAIL; - goto done; - } - - if (terminator == ':') { - // port terminator - bi->port = tmp; - - // next component must be the port, which may be terminated by an optional path, optional parameters, or the end of the uri - // which means checking if a '/' for path, or ';' for parameters - if (!(tmp2 = strpbrk(tmp, "/;"))) { - // none of the terminators are found, treat the remaining string as a port - goto done; - } - - terminator = *tmp2; - *tmp2++ = '\0'; - - tmp = tmp2; - - if (!(*bi->port)) { - ret = KS_STATUS_FAIL; - goto done; - } - - // @todo sscanf bi->port into bi->portnum and validate that it is a valid port number - } - - if (terminator == '/') { - // path terminator - bi->path = tmp; - - // next component must be the path, which may be terminated by optional parameters, or the end of the uri - // which means checking ';' for parameters - if (!(tmp2 = strpbrk(tmp, ";"))) { - // none of the terminators are found, treat the remaining string as a path - goto done; - } - - terminator = *tmp2; - *tmp2++ = '\0'; - - tmp = tmp2; - - if (!(*bi->path)) { - ret = KS_STATUS_FAIL; - goto done; - } - } - - if (terminator == ';') { - // parameter terminator - do { - char *key = NULL; - char *value = NULL; - - // next component must be the parameter key, which must be terminated by mandatory '=', end of the uri is an error - // which means checking '=' for key terminator - key = tmp; - if (!(tmp = strpbrk(tmp, "="))) { - ret = KS_STATUS_FAIL; - goto done; - } - *tmp++ = '\0'; - - // next component must be the parameter value, which may be terminated by another parameter terminator ';', or the end of the uri - // if it is the end of the uri, then the parameter loop will be exited - value = tmp; - if ((tmp = strpbrk(tmp, ";"))) { - *tmp++ = '\0'; - } - - // create th parameters hash if it does not already exist and add the parameter entry to it, note the key and value are both actually part - // of the duplicated uri for components and will be cleaned up with the single string so the hash must not free the key or value itself - if (!bi->parameters) ks_hash_create(&bi->parameters, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - ks_hash_insert(bi->parameters, (void *)key, (void *)value); - } while (tmp); - } - -done: - if (ret != KS_STATUS_SUCCESS) blade_identity_reset(bi); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_identity_uri_get(blade_identity_t *bi) -{ - ks_assert(bi); - - return bi->uri; -} - -KS_DECLARE(const char *) blade_identity_scheme_get(blade_identity_t *bi) -{ - ks_assert(bi); - - return bi->scheme; -} - -KS_DECLARE(const char *) blade_identity_user_get(blade_identity_t *bi) -{ - ks_assert(bi); - - return bi->user; -} - -KS_DECLARE(const char *) blade_identity_host_get(blade_identity_t *bi) -{ - ks_assert(bi); - - return bi->host; -} - -KS_DECLARE(const char *) blade_identity_port_get(blade_identity_t *bi) -{ - ks_assert(bi); - - return bi->port; -} - -KS_DECLARE(ks_port_t) blade_identity_portnum_get(blade_identity_t *bi) -{ - ks_assert(bi); - - return bi->portnum; -} - -KS_DECLARE(const char *) blade_identity_path_get(blade_identity_t *bi) -{ - ks_assert(bi); - - return bi->path; -} - -KS_DECLARE(const char *) blade_identity_parameter_lookup(blade_identity_t *bi, const char *key) -{ - ks_assert(bi); - ks_assert(key); - - if (!bi->parameters) return NULL; - - return (const char *)ks_hash_search(bi->parameters, (void *)key, KS_UNLOCKED); -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_mastermgr.c b/libs/libblade/src/blade_mastermgr.c deleted file mode 100644 index e719446b99..0000000000 --- a/libs/libblade/src/blade_mastermgr.c +++ /dev/null @@ -1,505 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_mastermgr_s { - blade_handle_t *handle; - - // @todo use a blade_mastermgr_config_t to store configuration, inline variable, with sane defaults for as much configuration as is possible - // then reuse this same pattern across all the manager types that invoke startup configuration processing - const char *master_nodeid; - // @todo how does "exclusive" play into the controllers, does "exclusive" mean only one provider can exist for a given protocol? what does non exclusive mean? - ks_hash_t *protocols; -}; - - -static void blade_mastermgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_mastermgr_t *bmmgr = (blade_mastermgr_t *)ptr; - - //ks_assert(bmmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_mastermgr_create(blade_mastermgr_t **bmmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_mastermgr_t *bmmgr = NULL; - - ks_assert(bmmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - bmmgr = ks_pool_alloc(pool, sizeof(blade_mastermgr_t)); - bmmgr->handle = bh; - - ks_hash_create(&bmmgr->protocols, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bmmgr->protocols); - - ks_pool_set_cleanup(bmmgr, NULL, blade_mastermgr_cleanup); - - *bmmgrP = bmmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_destroy(blade_mastermgr_t **bmmgrP) -{ - blade_mastermgr_t *bmmgr = NULL; - ks_pool_t *pool; - - ks_assert(bmmgrP); - ks_assert(*bmmgrP); - - bmmgr = *bmmgrP; - *bmmgrP = NULL; - - pool = ks_pool_get(bmmgr); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_mastermgr_handle_get(blade_mastermgr_t *bmmgr) -{ - ks_assert(bmmgr); - - return bmmgr->handle; -} - -ks_status_t blade_mastermgr_config(blade_mastermgr_t *bmmgr, config_setting_t *config) -{ - ks_pool_t *pool = NULL; - config_setting_t *master = NULL; - config_setting_t *master_nodeid = NULL; - const char *nodeid = NULL; - - ks_assert(bmmgr); - - pool = ks_pool_get(bmmgr); - - if (!config_setting_is_group(config)) { - ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n"); - return KS_STATUS_FAIL; - } - - master = config_setting_get_member(config, "master"); - if (master) { - master_nodeid = config_setting_lookup(master, "nodeid"); - if (!master_nodeid) return KS_STATUS_FAIL; - - if (config_setting_type(master_nodeid) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL; - nodeid = config_setting_get_string(master_nodeid); - } - - if (master) { - bmmgr->master_nodeid = ks_pstrdup(pool, nodeid); - - ks_log(KS_LOG_DEBUG, "Configured\n"); - } - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_startup(blade_mastermgr_t *bmmgr, config_setting_t *config) -{ - ks_assert(bmmgr); - - if (blade_mastermgr_config(bmmgr, config) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "blade_mastermgr_config failed\n"); - return KS_STATUS_FAIL; - } - - if (bmmgr->master_nodeid) { - blade_routemgr_local_set(blade_handle_routemgr_get(bmmgr->handle), bmmgr->master_nodeid); - blade_routemgr_master_set(blade_handle_routemgr_get(bmmgr->handle), bmmgr->master_nodeid); - - blade_mastermgr_protocol_controller_add(bmmgr, "blade.presence", bmmgr->master_nodeid); - - blade_mastermgr_protocol_channel_add(bmmgr, "blade.presence", "join", BLADE_CHANNEL_FLAGS_PUBLIC); - blade_mastermgr_protocol_channel_add(bmmgr, "blade.presence", "leave", BLADE_CHANNEL_FLAGS_PUBLIC); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_shutdown(blade_mastermgr_t *bmmgr) -{ - ks_assert(bmmgr); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_purge(blade_mastermgr_t *bmmgr, const char *nodeid) -{ - ks_pool_t *pool = NULL; - ks_hash_t *cleanup = NULL; - - ks_assert(bmmgr); - - pool = ks_pool_get(bmmgr); - - ks_hash_write_lock(bmmgr->protocols); - - for (ks_hash_iterator_t *it = ks_hash_first(bmmgr->protocols, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *protocol = NULL; - blade_protocol_t *bp = NULL; - ks_bool_t unlock = KS_TRUE; - - ks_hash_this(it, (const void **)&protocol, NULL, (void **)&bp); - - blade_protocol_write_lock(bp); - - if (blade_protocol_purge(bp, nodeid)) { - if (!blade_protocol_controller_available(bp)) { - if (!cleanup) ks_hash_create(&cleanup, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - ks_hash_insert(cleanup, (void *)protocol, bp); - unlock = KS_FALSE; - } - else { - // @todo not the last controller, may need to propagate that the controller is no longer available? - } - } - if (unlock) blade_protocol_write_unlock(bp); - } - - if (cleanup) { - for (ks_hash_iterator_t *it2 = ks_hash_first(cleanup, KS_UNLOCKED); it2; it2 = ks_hash_next(&it2)) { - const char *protocol = NULL; - blade_protocol_t *bp = NULL; - - ks_hash_this(it2, (const void **)&protocol, NULL, (void **)&bp); - - blade_subscriptionmgr_broadcast(blade_handle_subscriptionmgr_get(bmmgr->handle), BLADE_RPCBROADCAST_COMMAND_PROTOCOL_REMOVE, NULL, protocol, NULL, NULL, NULL, NULL, NULL); - - ks_log(KS_LOG_DEBUG, "Protocol Removed: %s\n", protocol); - blade_protocol_write_unlock(bp); - - ks_hash_remove(bmmgr->protocols, (void *)protocol); - } - ks_hash_destroy(&cleanup); - } - - ks_hash_write_unlock(bmmgr->protocols); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_protocol_t *) blade_mastermgr_protocol_lookup(blade_mastermgr_t *bmmgr, const char *protocol, ks_bool_t writelocked) -{ - blade_protocol_t *bp = NULL; - - ks_assert(bmmgr); - ks_assert(protocol); - - bp = (blade_protocol_t *)ks_hash_search(bmmgr->protocols, (void *)protocol, KS_READLOCKED); - if (bp) { - if (writelocked) blade_protocol_write_lock(bp); - else blade_protocol_read_lock(bp); - } - ks_hash_read_unlock(bmmgr->protocols); - - return bp; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_controller_add(blade_mastermgr_t *bmmgr, const char *protocol, const char *controller) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_t *pool = NULL; - blade_protocol_t *bp = NULL; - - ks_assert(bmmgr); - ks_assert(protocol); - ks_assert(controller); - - pool = ks_pool_get(bmmgr); - - ks_hash_write_lock(bmmgr->protocols); - - bp = (blade_protocol_t *)ks_hash_search(bmmgr->protocols, (void *)protocol, KS_UNLOCKED); - - if (bp) blade_protocol_write_lock(bp); - else { - blade_protocol_create(&bp, pool, protocol); - ks_assert(bp); - - blade_protocol_write_lock(bp); - - ks_log(KS_LOG_DEBUG, "Protocol Added: %s\n", protocol); - ks_hash_insert(bmmgr->protocols, (void *)ks_pstrdup(ks_pool_get(bmmgr), protocol), (void *)bp); - } - - blade_protocol_controller_add(bp, controller); - - ks_log(KS_LOG_DEBUG, "Protocol Controller Added: %s to %s\n", controller, protocol); - - blade_protocol_write_unlock(bp); - - ks_hash_write_unlock(bmmgr->protocols); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_controller_remove(blade_mastermgr_t *bmmgr, const char *protocol, const char *controller) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_protocol_t *bp = NULL; - ks_bool_t remove = KS_FALSE; - - ks_assert(bmmgr); - ks_assert(protocol); - ks_assert(controller); - - ks_hash_write_lock(bmmgr->protocols); - - bp = (blade_protocol_t *)ks_hash_search(bmmgr->protocols, (void *)protocol, KS_UNLOCKED); - if (!bp) { - ret = KS_STATUS_NOT_FOUND; - goto done; - } - - blade_protocol_write_lock(bp); - - if (blade_protocol_controller_remove(bp, controller)) { - ks_log(KS_LOG_DEBUG, "Protocol Controller Removed: %s from %s\n", controller, protocol); - if (!blade_protocol_controller_available(bp)) { - blade_subscriptionmgr_broadcast(blade_handle_subscriptionmgr_get(bmmgr->handle), BLADE_RPCBROADCAST_COMMAND_PROTOCOL_REMOVE, NULL, protocol, NULL, NULL, NULL, NULL, NULL); - - ks_log(KS_LOG_DEBUG, "Protocol Removed: %s\n", protocol); - remove = KS_TRUE; - } else { - // @todo not the last controller, may need to propagate when a specific controller becomes unavailable though - } - } - - blade_protocol_write_unlock(bp); - - if (remove) ks_hash_remove(bmmgr->protocols, (void *)protocol); - -done: - ks_hash_write_unlock(bmmgr->protocols); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_channel_add(blade_mastermgr_t *bmmgr, const char *protocol, const char *channel, blade_channel_flags_t flags) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_protocol_t *bp = NULL; - blade_channel_t *bc = NULL; - - ks_assert(bmmgr); - ks_assert(protocol); - ks_assert(channel); - - ks_hash_read_lock(bmmgr->protocols); - - bp = (blade_protocol_t *)ks_hash_search(bmmgr->protocols, (void *)protocol, KS_UNLOCKED); - if (!bp) { - ret = KS_STATUS_NOT_FOUND; - goto done; - } - - blade_protocol_write_lock(bp); - - bc = blade_protocol_channel_lookup(bp, channel, KS_TRUE); - if (bc) { - ret = KS_STATUS_DUPLICATE_OPERATION; - goto done; - } - - blade_channel_create(&bc, ks_pool_get(bp), channel, flags); - ks_assert(bc); - - blade_channel_write_lock(bc); - - if (blade_protocol_channel_add(bp, bc) == KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Protocol Channel Added: %s to %s\n", blade_channel_name_get(bc), blade_protocol_name_get(bp)); - } - -done: - if (bc) blade_channel_write_unlock(bc); - if (bp) blade_protocol_write_unlock(bp); - ks_hash_read_unlock(bmmgr->protocols); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_channel_remove(blade_mastermgr_t *bmmgr, const char *protocol, const char *channel) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_protocol_t *bp = NULL; - blade_channel_t *bc = NULL; - - ks_assert(bmmgr); - ks_assert(protocol); - ks_assert(channel); - - ks_hash_read_lock(bmmgr->protocols); - - bp = (blade_protocol_t *)ks_hash_search(bmmgr->protocols, (void *)protocol, KS_UNLOCKED); - if (!bp) { - ret = KS_STATUS_NOT_FOUND; - goto done; - } - - blade_protocol_write_lock(bp); - - bc = blade_protocol_channel_lookup(bp, channel, KS_TRUE); - if (!bc) { - ret = KS_STATUS_NOT_FOUND; - goto done; - } - - if (blade_protocol_channel_remove(bp, channel)) { - blade_subscriptionmgr_broadcast(blade_handle_subscriptionmgr_get(bmmgr->handle), BLADE_RPCBROADCAST_COMMAND_CHANNEL_REMOVE, NULL, protocol, channel, NULL, NULL, NULL, NULL); - ks_log(KS_LOG_DEBUG, "Protocol Channel Removed: %s from %s\n", blade_channel_name_get(bc), blade_protocol_name_get(bp)); - blade_channel_write_unlock(bc); - blade_channel_destroy(&bc); - } - -done: - if (bp) blade_protocol_write_unlock(bp); - ks_hash_read_unlock(bmmgr->protocols); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_channel_authorize(blade_mastermgr_t *bmmgr, ks_bool_t remove, const char *protocol, const char *channel, const char *controller, const char *target) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_protocol_t *bp = NULL; - blade_channel_t *bc = NULL; - - ks_assert(bmmgr); - ks_assert(protocol); - ks_assert(channel); - ks_assert(controller); - ks_assert(target); - - ks_hash_read_lock(bmmgr->protocols); - - bp = (blade_protocol_t *)ks_hash_search(bmmgr->protocols, (void *)protocol, KS_UNLOCKED); - if (!bp) { - ret = KS_STATUS_NOT_FOUND; - goto done; - } - - blade_protocol_read_lock(bp); - - if (!blade_protocol_controller_verify(bp, controller)) { - ret = KS_STATUS_NOT_ALLOWED; - goto done; - } - - bc = blade_protocol_channel_lookup(bp, channel, KS_TRUE); - if (!bc) { - ret = KS_STATUS_NOT_FOUND; - goto done; - } - - if (remove) { - if (blade_channel_authorization_remove(bc, target)) { - ks_log(KS_LOG_DEBUG, "Protocol Channel Authorization Removed: %s from protocol %s, channel %s\n", target, blade_protocol_name_get(bp), blade_channel_name_get(bc)); - } else ret = KS_STATUS_NOT_FOUND; - } else { - if (blade_channel_authorization_add(bc, target)) { - ks_log(KS_LOG_DEBUG, "Protocol Channel Authorization Added: %s to protocol %s, channel %s\n", target, blade_protocol_name_get(bp), blade_channel_name_get(bc)); - } - } - -done: - if (bc) blade_channel_write_unlock(bc); - if (bp) blade_protocol_read_unlock(bp); - ks_hash_read_unlock(bmmgr->protocols); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_mastermgr_protocol_channel_authorization_verify(blade_mastermgr_t *bmmgr, const char *protocol, const char *channel, const char *target) -{ - ks_bool_t ret = KS_FALSE; - blade_protocol_t *bp = NULL; - blade_channel_t *bc = NULL; - - ks_assert(bmmgr); - ks_assert(protocol); - ks_assert(channel); - ks_assert(target); - - ks_hash_read_lock(bmmgr->protocols); - - bp = (blade_protocol_t *)ks_hash_search(bmmgr->protocols, (void *)protocol, KS_UNLOCKED); - if (!bp) { - ret = KS_FALSE; - goto done; - } - - blade_protocol_read_lock(bp); - - bc = blade_protocol_channel_lookup(bp, channel, KS_FALSE); - if (!bc) { - ret = KS_FALSE; - goto done; - } - - if ((blade_channel_flags_get(bc) & BLADE_CHANNEL_FLAGS_PUBLIC) == BLADE_CHANNEL_FLAGS_PUBLIC) ret = KS_TRUE; - else ret = blade_channel_authorization_verify(bc, target); - -done: - if (bc) blade_channel_read_unlock(bc); - if (bp) blade_protocol_read_unlock(bp); - ks_hash_read_unlock(bmmgr->protocols); - - return ret; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_protocol.c b/libs/libblade/src/blade_protocol.c deleted file mode 100644 index 20ca5d91f1..0000000000 --- a/libs/libblade/src/blade_protocol.c +++ /dev/null @@ -1,289 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_protocol_s { - const char *name; - ks_rwl_t *lock; - ks_hash_t *controllers; - ks_hash_t *channels; - // @todo descriptors (schema, etc) for each method within a protocol -}; - - -static void blade_protocol_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_protocol_t *bp = (blade_protocol_t *)ptr; - - ks_assert(bp); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (bp->name) ks_pool_free(&bp->name); - if (bp->lock) ks_rwl_destroy(&bp->lock); - if (bp->controllers) ks_hash_destroy(&bp->controllers); - if (bp->channels) ks_hash_destroy(&bp->channels); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_protocol_create(blade_protocol_t **bpP, ks_pool_t *pool, const char *name) -{ - blade_protocol_t *bp = NULL; - - ks_assert(bpP); - ks_assert(pool); - ks_assert(name); - - bp = ks_pool_alloc(pool, sizeof(blade_protocol_t)); - bp->name = ks_pstrdup(pool, name); - - ks_rwl_create(&bp->lock, pool); - ks_assert(bp->lock); - - ks_hash_create(&bp->controllers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bp->controllers); - - ks_hash_create(&bp->channels, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bp->channels); - - ks_pool_set_cleanup(bp, NULL, blade_protocol_cleanup); - - *bpP = bp; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_protocol_destroy(blade_protocol_t **bpP) -{ - ks_assert(bpP); - ks_assert(*bpP); - - ks_pool_free(bpP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_protocol_name_get(blade_protocol_t *bp) -{ - ks_assert(bp); - return bp->name; -} - -KS_DECLARE(ks_status_t) blade_protocol_read_lock(blade_protocol_t *bp) -{ - ks_assert(bp); - return ks_rwl_read_lock(bp->lock); -} - -KS_DECLARE(ks_status_t) blade_protocol_read_unlock(blade_protocol_t *bp) -{ - ks_assert(bp); - return ks_rwl_read_unlock(bp->lock); -} - -KS_DECLARE(ks_status_t) blade_protocol_write_lock(blade_protocol_t *bp) -{ - ks_assert(bp); - return ks_rwl_write_lock(bp->lock); -} - -KS_DECLARE(ks_status_t) blade_protocol_write_unlock(blade_protocol_t *bp) -{ - ks_assert(bp); - return ks_rwl_write_unlock(bp->lock); -} - -KS_DECLARE(ks_bool_t) blade_protocol_purge(blade_protocol_t *bp, const char *nodeid) -{ - ks_bool_t ret = KS_FALSE; - ks_assert(bp); - ks_assert(nodeid); - - // @todo iterate all channels, remove the nodeid from all authorized hashes - ks_hash_write_lock(bp->channels); - for (ks_hash_iterator_t *it = ks_hash_first(bp->channels, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key = NULL; - blade_channel_t *channel = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&channel); - - if (blade_channel_authorization_remove(channel, nodeid)) { - ks_log(KS_LOG_DEBUG, "Protocol Channel Authorization Removed: %s from protocol %s, channel %s\n", nodeid, bp->name, key); - } - } - ks_hash_write_unlock(bp->channels); - - if ((ret = blade_protocol_controller_remove(bp, nodeid))) { - ks_log(KS_LOG_DEBUG, "Protocol Controller Removed: %s from %s\n", nodeid, bp->name); - } - - return ret; -} - -KS_DECLARE(cJSON *) blade_protocol_controller_pack(blade_protocol_t *bp) -{ - cJSON *controllers = cJSON_CreateObject(); - - ks_assert(bp); - - ks_hash_read_lock(bp->controllers); - for (ks_hash_iterator_t *it = ks_hash_first(bp->controllers, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - - cJSON_AddItemToArray(controllers, cJSON_CreateString(key)); - } - ks_hash_read_unlock(bp->controllers); - - return controllers; -} - -KS_DECLARE(ks_bool_t) blade_protocol_controller_verify(blade_protocol_t *bp, const char *controller) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(bp); - ks_assert(controller); - - ret = (ks_bool_t)(uintptr_t)ks_hash_search(bp->controllers, (void *)controller, KS_READLOCKED); - ks_hash_read_unlock(bp->controllers); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_protocol_controller_add(blade_protocol_t *bp, const char *nodeid) -{ - char *key = NULL; - - ks_assert(bp); - ks_assert(nodeid); - - key = ks_pstrdup(ks_pool_get(bp), nodeid); - ks_hash_insert(bp->controllers, (void *)key, (void *)KS_TRUE); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_bool_t) blade_protocol_controller_remove(blade_protocol_t *bp, const char *nodeid) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(bp); - ks_assert(nodeid); - - ks_hash_write_lock(bp->controllers); - if (ks_hash_remove(bp->controllers, (void *)nodeid)) { - ret = KS_TRUE; - } - ks_hash_write_unlock(bp->controllers); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_protocol_controller_available(blade_protocol_t *bp) -{ - ks_assert(bp); - return ks_hash_count(bp->controllers) > 0; -} - -KS_DECLARE(blade_channel_t *) blade_protocol_channel_lookup(blade_protocol_t *bp, const char *channel, ks_bool_t writelocked) -{ - blade_channel_t *bc = NULL; - - ks_assert(bp); - ks_assert(channel); - - bc = (blade_channel_t *)ks_hash_search(bp->channels, (void *)channel, KS_READLOCKED); - if (bc) { - if (writelocked) blade_channel_write_lock(bc); - else blade_channel_read_lock(bc); - } - ks_hash_read_unlock(bp->channels); - - return bc; -} - -KS_DECLARE(ks_status_t) blade_protocol_channel_add(blade_protocol_t *bp, blade_channel_t *channel) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_t *pool = NULL; - char *key = NULL; - - ks_assert(bp); - ks_assert(channel); - - pool = ks_pool_get(bp); - - ks_hash_write_lock(bp->channels); - - if (ks_hash_search(bp->channels, (void *)blade_channel_name_get(channel), KS_UNLOCKED)) { - ret = KS_STATUS_DUPLICATE_OPERATION; - goto done; - } - - key = ks_pstrdup(pool, blade_channel_name_get(channel)); - ks_hash_insert(bp->channels, (void *)key, (void *)channel); - -done: - - ks_hash_write_unlock(bp->channels); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_protocol_channel_remove(blade_protocol_t *bp, const char *channel) -{ - ks_assert(bp); - ks_assert(channel); - - return ks_hash_remove(bp->channels, (void *)channel) != NULL; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_restmgr.c b/libs/libblade/src/blade_restmgr.c deleted file mode 100644 index 2c2d43a2ef..0000000000 --- a/libs/libblade/src/blade_restmgr.c +++ /dev/null @@ -1,562 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -#define BLADE_RESTMGR_SERVICE_CAPTURE_MAX 10 -#define BLADE_RESTMGR_SERVICE_CAPTURE_VECTORS (BLADE_RESTMGR_SERVICE_CAPTURE_MAX * 3) // @note Last third of this is workspace - -typedef struct blade_restmgr_config_s { - ks_bool_t enabled; - - ks_hash_t *options; -} blade_restmgr_config_t; - -struct blade_restmgr_s { - blade_handle_t *handle; - - blade_restmgr_config_t config; - - void *data; - - struct mg_context *context; - - ks_hash_t *services; -}; - -typedef struct blade_restmgr_service_s { - pcre *compiled; - pcre_extra *extra; - const char *action; - blade_restmgr_service_callback_t callback; -} blade_restmgr_service_t; - - -static void blade_restmgr_service_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_restmgr_service_t *brestmgrs = (blade_restmgr_service_t *)ptr; - - ks_assert(brestmgrs); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (brestmgrs->compiled) { - pcre_free(brestmgrs->compiled); - brestmgrs->compiled = NULL; - } - if (brestmgrs->extra) { -#ifdef PCRE_CONFIG_JIT - pcre_free_study(brestmgrs->extra); -#else - pcre_free(brestmgrs->extra); -#endif - brestmgrs->extra = NULL; - } - if (brestmgrs->action) ks_pool_free(&brestmgrs->action); - break; - case KS_MPCL_DESTROY: - break; - } -} - -int blade_restmgr_handle_begin_request(struct mg_connection *conn); -void blade_restmgr_handle_end_request(const struct mg_connection *conn, int reply_status_code); -int blade_restmgr_handle_log_message(const struct mg_connection *conn, const char *message); -int blade_restmgr_handle_log_access(const struct mg_connection *conn, const char *message); -int blade_restmgr_handle_init_ssl(void *ssl_context, void *user_data); -void blade_restmgr_handle_connection_close(const struct mg_connection *conn); -const char *blade_restmgr_handle_open_file(const struct mg_connection *conn, const char *path, size_t *data_len); -void blade_restmgr_handle_init_lua(const struct mg_connection *conn, void *lua_context); -int blade_restmgr_handle_http_error(struct mg_connection *conn, int status); -void blade_restmgr_handle_init_context(const struct mg_context *ctx); -void blade_restmgr_handle_init_thread(const struct mg_context *ctx, int thread_type); -void blade_restmgr_handle_exit_context(const struct mg_context *ctx); - - -static void blade_restmgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_restmgr_t *brestmgr = (blade_restmgr_t *)ptr; - - //ks_assert(brestmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_restmgr_create(blade_restmgr_t **brestmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_restmgr_t *brestmgr = NULL; - - ks_assert(brestmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - brestmgr = ks_pool_alloc(pool, sizeof(blade_restmgr_t)); - brestmgr->handle = bh; - - ks_hash_create(&brestmgr->config.options, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - ks_assert(brestmgr->config.options); - - ks_hash_create(&brestmgr->services, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(brestmgr->services); - - ks_pool_set_cleanup(brestmgr, NULL, blade_restmgr_cleanup); - - *brestmgrP = brestmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_restmgr_destroy(blade_restmgr_t **brestmgrP) -{ - blade_restmgr_t *brestmgr = NULL; - ks_pool_t *pool; - - ks_assert(brestmgrP); - ks_assert(*brestmgrP); - - brestmgr = *brestmgrP; - *brestmgrP = NULL; - - pool = ks_pool_get(brestmgr); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -#define CONFIG_LOADSTR(k) \ -tmp = config_setting_lookup(rest, k); \ -if (tmp && config_setting_type(tmp) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL; \ -if (tmp) ks_hash_insert(brestmgr->config.options, (void *)k, (void *)ks_pstrdup(pool, config_setting_get_string(tmp))); - -ks_status_t blade_restmgr_config(blade_restmgr_t *brestmgr, config_setting_t *config) -{ - ks_pool_t *pool = NULL; - config_setting_t *rest = NULL; - config_setting_t *tmp = NULL; - - ks_assert(brestmgr); - - pool = ks_pool_get(brestmgr); - - if (!config_setting_is_group(config)) { - ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n"); - return KS_STATUS_FAIL; - } - - rest = config_setting_get_member(config, "rest"); - if (rest) { - tmp = config_setting_lookup(rest, "enabled"); - if (!tmp) return KS_STATUS_FAIL; - - if (config_setting_type(tmp) != CONFIG_TYPE_BOOL) return KS_STATUS_FAIL; - brestmgr->config.enabled = config_setting_get_bool(tmp); - if (!brestmgr->config.enabled) return KS_STATUS_SUCCESS; - - CONFIG_LOADSTR("cgi_pattern"); - CONFIG_LOADSTR("cgi_environment"); - CONFIG_LOADSTR("put_delete_auth_file"); - CONFIG_LOADSTR("cgi_interpreter"); - CONFIG_LOADSTR("protect_uri"); - CONFIG_LOADSTR("authentication_domain"); - CONFIG_LOADSTR("enable_auth_domain_check"); - CONFIG_LOADSTR("ssi_pattern"); - CONFIG_LOADSTR("throttle"); - CONFIG_LOADSTR("access_log_file"); - CONFIG_LOADSTR("enable_directory_listing"); - CONFIG_LOADSTR("error_log_file"); - CONFIG_LOADSTR("global_auth_file"); - CONFIG_LOADSTR("index_files"); - CONFIG_LOADSTR("enable_keep_alive"); - CONFIG_LOADSTR("access_control_list"); - CONFIG_LOADSTR("extra_mime_types"); - CONFIG_LOADSTR("listening_ports"); - CONFIG_LOADSTR("document_root"); - CONFIG_LOADSTR("ssl_certificate"); - CONFIG_LOADSTR("ssl_certificate_chain"); - CONFIG_LOADSTR("num_threads"); - CONFIG_LOADSTR("run_as_user"); - CONFIG_LOADSTR("url_rewrite_patterns"); - CONFIG_LOADSTR("hide_files_patterns"); - CONFIG_LOADSTR("request_timeout_ms"); - CONFIG_LOADSTR("keep_alive_timeout_ms"); - CONFIG_LOADSTR("linger_timeout_ms"); - CONFIG_LOADSTR("ssl_verify_peer"); - CONFIG_LOADSTR("ssl_ca_path"); - CONFIG_LOADSTR("ssl_ca_file"); - CONFIG_LOADSTR("ssl_verify_depth"); - CONFIG_LOADSTR("ssl_default_verify_paths"); - CONFIG_LOADSTR("ssl_cipher_list"); - CONFIG_LOADSTR("ssl_protocol_version"); - CONFIG_LOADSTR("ssl_short_trust"); - CONFIG_LOADSTR("websocket_timeout_ms"); - CONFIG_LOADSTR("decode_url"); - CONFIG_LOADSTR("lua_preload_file"); - CONFIG_LOADSTR("lua_script_pattern"); - CONFIG_LOADSTR("lua_server_page_pattern"); - CONFIG_LOADSTR("duktape_script_pattern"); - CONFIG_LOADSTR("websocket_root"); - CONFIG_LOADSTR("lua_websocket_pattern"); - CONFIG_LOADSTR("access_control_allow_origin"); - CONFIG_LOADSTR("access_control_allow_methods"); - CONFIG_LOADSTR("access_control_allow_headers"); - CONFIG_LOADSTR("error_pages"); - CONFIG_LOADSTR("tcp_nodelay"); - CONFIG_LOADSTR("static_file_max_age"); - CONFIG_LOADSTR("strict_transport_security_max_age"); - CONFIG_LOADSTR("allow_sendfile_call"); - CONFIG_LOADSTR("case_sensitive"); - CONFIG_LOADSTR("lua_background_script"); - CONFIG_LOADSTR("lua_background_script_params"); - CONFIG_LOADSTR("additional_header"); - CONFIG_LOADSTR("max_request_size"); - CONFIG_LOADSTR("allow_index_script_resource"); - } - - if (brestmgr->config.enabled) { - ks_log(KS_LOG_DEBUG, "Configured\n"); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_restmgr_startup(blade_restmgr_t *brestmgr, config_setting_t *config) -{ - ks_assert(brestmgr); - - if (blade_restmgr_config(brestmgr, config) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "blade_restmgr_config failed\n"); - return KS_STATUS_FAIL; - } - - if (brestmgr->config.enabled) { - struct mg_callbacks callbacks; - const char **options = (const char **)ks_pool_calloc(ks_pool_get(brestmgr), (ks_hash_count(brestmgr->config.options) * 2) + 1, sizeof(char *)); - ks_size_t index = 0; - - memset(&callbacks, 0, sizeof(struct mg_callbacks)); - callbacks.begin_request = blade_restmgr_handle_begin_request; - callbacks.end_request = blade_restmgr_handle_end_request; - callbacks.log_message = blade_restmgr_handle_log_message; - callbacks.log_access = blade_restmgr_handle_log_access; - //callbacks.init_ssl = blade_restmgr_handle_init_ssl; - callbacks.connection_close = blade_restmgr_handle_connection_close; - callbacks.open_file = blade_restmgr_handle_open_file; - callbacks.init_lua = blade_restmgr_handle_init_lua; - callbacks.http_error = blade_restmgr_handle_http_error; - callbacks.init_context = blade_restmgr_handle_init_context; - callbacks.init_thread = blade_restmgr_handle_init_thread; - callbacks.exit_context = blade_restmgr_handle_exit_context; - - for (ks_hash_iterator_t *it = ks_hash_first(brestmgr->config.options, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key = NULL; - const char *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - options[index++] = key; - options[index++] = value; - } - options[index++] = NULL; - - brestmgr->context = mg_start(&callbacks, brestmgr, options); - - ks_pool_free(&options); - - if (!brestmgr->context) return KS_STATUS_FAIL; - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_restmgr_shutdown(blade_restmgr_t *brestmgr) -{ - ks_assert(brestmgr); - if (brestmgr->context) { - mg_stop(brestmgr->context); - brestmgr->context = NULL; - } - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_restmgr_handle_get(blade_restmgr_t *brestmgr) -{ - ks_assert(brestmgr); - - return brestmgr->handle; -} - -KS_DECLARE(void *) blade_restmgr_data_get(blade_restmgr_t *brestmgr) -{ - ks_assert(brestmgr); - - return brestmgr->data; -} - -KS_DECLARE(ks_status_t) blade_restmgr_data_set(blade_restmgr_t *brestmgr, void *data) -{ - ks_assert(brestmgr); - - brestmgr->data = data; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_restmgr_service_add(blade_restmgr_t *brestmgr, const char *action, const char *route, blade_restmgr_service_callback_t callback) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_t *pool = NULL; - char *key = NULL; - blade_restmgr_service_t *service = NULL; - const char *errString = NULL; - int errOffset = 0; - - ks_assert(brestmgr); - ks_assert(route); - ks_assert(callback); - - pool = ks_pool_get(brestmgr); - - key = ks_psprintf(pool, "%s:%s", action, route); - - ks_hash_write_lock(brestmgr->services); - - if ((service = (blade_restmgr_service_t *)ks_hash_remove(brestmgr->services, (void *)key)) != NULL) { - ks_log(KS_LOG_DEBUG, "Service Removed: %s\n", key); - ks_pool_free(&service); - } - - service = ks_pool_alloc(pool, sizeof(blade_restmgr_service_t)); - ks_pool_set_cleanup(service, NULL, blade_restmgr_service_cleanup); - - service->callback = callback; - service->action = ks_pstrdup(pool, action); - - service->compiled = pcre_compile(route, 0, &errString, &errOffset, NULL); - if (service->compiled == NULL) { - ks_log(KS_LOG_DEBUG, "Could not compile '%s': %s\n", route, errString); - ret = KS_STATUS_FAIL; - goto done; - } - - service->extra = pcre_study(service->compiled, 0, &errString); - if (errString != NULL) { - ks_log(KS_LOG_DEBUG, "Could not study '%s': %s\n", route, errString); - ret = KS_STATUS_FAIL; - goto done; - } - - ks_hash_insert(brestmgr->services, (void *)key, (void *)service); - - ks_log(KS_LOG_DEBUG, "Service Added: %s\n", key); - -done: - ks_hash_write_unlock(brestmgr->services); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_restmgr_service_remove(blade_restmgr_t *brestmgr, const char *action, const char *route) -{ - ks_pool_t *pool = NULL; - const char *key = NULL; - blade_restmgr_service_t *service = NULL; - - ks_assert(brestmgr); - ks_assert(route); - - pool = ks_pool_get(brestmgr); - - key = ks_psprintf(pool, "%s:%s", action, route); - - if ((service = (blade_restmgr_service_t *)ks_hash_remove(brestmgr->services, (void *)key)) != NULL) { - ks_log(KS_LOG_DEBUG, "Service Removed: %s\n", key); - ks_pool_free(&service); - } - - ks_pool_free(&key); - - return KS_STATUS_SUCCESS; -} - - -int blade_restmgr_handle_begin_request(struct mg_connection *conn) -{ - int ret = 0; - blade_restmgr_t *brestmgr = NULL; - const struct mg_request_info *info = NULL; - int execRet = 0; - int captureVectors[BLADE_RESTMGR_SERVICE_CAPTURE_VECTORS]; - - info = mg_get_request_info(conn); - - ks_log(KS_LOG_DEBUG, "Request for: %s on %s\n", info->request_uri, info->request_method); - - brestmgr = (blade_restmgr_t *)info->user_data; - - ks_hash_read_lock(brestmgr->services); - - for (ks_hash_iterator_t *it = ks_hash_first(brestmgr->services, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key = NULL; - blade_restmgr_service_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - // @todo could optimize this to provide a separate hash for each action typed, keyed in a top level hash by the request_method/action string - if (ks_safe_strcasecmp(value->action, info->request_method)) continue; - - execRet = pcre_exec(value->compiled, - value->extra, - info->request_uri, - strlen(info->request_uri), - 0, // Offset - 0, // Options - captureVectors, - BLADE_RESTMGR_SERVICE_CAPTURE_VECTORS); - - if (execRet < 0) { - switch (execRet) { - case PCRE_ERROR_NOMATCH: continue; - case PCRE_ERROR_NULL: ks_log(KS_LOG_DEBUG, "Something was null\n"); break; - case PCRE_ERROR_BADOPTION: ks_log(KS_LOG_DEBUG, "A bad option was passed\n"); break; - case PCRE_ERROR_BADMAGIC: ks_log(KS_LOG_DEBUG, "Magic number bad (compile corrupt?)\n"); break; - case PCRE_ERROR_UNKNOWN_NODE: ks_log(KS_LOG_DEBUG, "Something kooky in the compile\n"); break; - case PCRE_ERROR_NOMEMORY: ks_log(KS_LOG_DEBUG, "Ran out of memory\n"); break; - default: ks_log(KS_LOG_DEBUG, "Unknown error\n"); break; - } - ret = 500; - goto done; - } else { - const char **captures = NULL; - - if (execRet == 0) { - ks_log(KS_LOG_DEBUG, "Too many substrings were found to fit in capture vectors!\n"); - ret = 500; - goto done; - } - - if (pcre_get_substring_list(info->request_uri, captureVectors, execRet, &captures) != 0) { - ks_log(KS_LOG_DEBUG, "Cannot get substring list!\n"); - ret = 500; - goto done; - } - - ret = value->callback(brestmgr, conn, captures); - - pcre_free_substring_list(captures); - //ret = 200; - goto done; - } - } - -done: - ks_hash_read_unlock(brestmgr->services); - - return ret; -} - -void blade_restmgr_handle_end_request(const struct mg_connection *conn, int reply_status_code) -{ - -} - -int blade_restmgr_handle_log_message(const struct mg_connection *conn, const char *message) -{ - return 0; -} - -int blade_restmgr_handle_log_access(const struct mg_connection *conn, const char *message) -{ - return 0; -} - -int blade_restmgr_handle_init_ssl(void *ssl_context, void *user_data) -{ - return 0; -} - -void blade_restmgr_handle_connection_close(const struct mg_connection *conn) -{ - -} - -const char *blade_restmgr_handle_open_file(const struct mg_connection *conn, const char *path, size_t *data_len) -{ - return NULL; -} - -void blade_restmgr_handle_init_lua(const struct mg_connection *conn, void *lua_context) -{ - -} - -int blade_restmgr_handle_http_error(struct mg_connection *conn, int status) -{ - return 1; -} - -void blade_restmgr_handle_init_context(const struct mg_context *ctx) -{ - -} - -void blade_restmgr_handle_init_thread(const struct mg_context *ctx, int thread_type) -{ - -} - -void blade_restmgr_handle_exit_context(const struct mg_context *ctx) -{ - -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_routemgr.c b/libs/libblade/src/blade_routemgr.c deleted file mode 100644 index af3149d921..0000000000 --- a/libs/libblade/src/blade_routemgr.c +++ /dev/null @@ -1,533 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_routemgr_s { - blade_handle_t *handle; - - const char *local_nodeid; - ks_rwl_t *local_lock; - - const char *master_nodeid; - ks_rwl_t *master_lock; - - ks_hash_t *routes; // target nodeid, downstream router nodeid - ks_hash_t *identities; // identity, target nodeid -}; - - -static void blade_routemgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_routemgr_t *brmgr = (blade_routemgr_t *)ptr; - - //ks_assert(brmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_routemgr_create(blade_routemgr_t **brmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_routemgr_t *brmgr = NULL; - - ks_assert(brmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - brmgr = ks_pool_alloc(pool, sizeof(blade_routemgr_t)); - brmgr->handle = bh; - - ks_rwl_create(&brmgr->local_lock, pool); - ks_assert(brmgr->local_lock); - - ks_rwl_create(&brmgr->master_lock, pool); - ks_assert(brmgr->master_lock); - - // @note can let removes free keys and values for routes and identity, both use keys and values that are strings allocated from the same pool as the hash itself - ks_hash_create(&brmgr->routes, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(brmgr->routes); - - ks_hash_create(&brmgr->identities, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(brmgr->routes); - - ks_pool_set_cleanup(brmgr, NULL, blade_routemgr_cleanup); - - *brmgrP = brmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_routemgr_destroy(blade_routemgr_t **brmgrP) -{ - blade_routemgr_t *brmgr = NULL; - ks_pool_t *pool; - - ks_assert(brmgrP); - ks_assert(*brmgrP); - - brmgr = *brmgrP; - *brmgrP = NULL; - - pool = ks_pool_get(brmgr); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_routemgr_handle_get(blade_routemgr_t *brmgr) -{ - ks_assert(brmgr); - - return brmgr->handle; -} - -KS_DECLARE(ks_status_t) blade_routemgr_local_set(blade_routemgr_t *brmgr, const char *nodeid) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(brmgr); - - ks_rwl_write_lock(brmgr->local_lock); - - if (brmgr->local_nodeid) ks_pool_free(&brmgr->local_nodeid); - if (nodeid) brmgr->local_nodeid = ks_pstrdup(ks_pool_get(brmgr), nodeid); - - ks_log(KS_LOG_DEBUG, "Local NodeID: %s\n", nodeid); - - ks_rwl_write_unlock(brmgr->local_lock); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_routemgr_local_check(blade_routemgr_t *brmgr, const char *target) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(brmgr); - ks_assert(target); - - ks_rwl_read_lock(brmgr->local_lock); - - ret = !ks_safe_strcasecmp(brmgr->local_nodeid, target); - - if (!ret) { - // @todo must parse target to an identity, and back to a properly formatted identity key - blade_identity_t *identity = NULL; - ks_pool_t *pool = ks_pool_get(brmgr); - - blade_identity_create(&identity, pool); - if (blade_identity_parse(identity, target) == KS_STATUS_SUCCESS) { - char *key = ks_psprintf(pool, "%s@%s/%s", blade_identity_user_get(identity), blade_identity_host_get(identity), blade_identity_path_get(identity)); - const char *value = (const char *)ks_hash_search(brmgr->identities, (void *)key, KS_READLOCKED); - - if (value) ret = !ks_safe_strcasecmp(brmgr->local_nodeid, value); - - ks_hash_read_unlock(brmgr->identities); - - ks_pool_free(&key); - } - - blade_identity_destroy(&identity); - } - - ks_rwl_read_unlock(brmgr->local_lock); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_routemgr_local_copy(blade_routemgr_t *brmgr, const char **nodeid) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(brmgr); - ks_assert(nodeid); - - *nodeid = NULL; - - ks_rwl_read_lock(brmgr->local_lock); - - if (brmgr->local_nodeid) { - ret = KS_TRUE; - *nodeid = ks_pstrdup(ks_pool_get(brmgr), brmgr->local_nodeid); - } - - ks_rwl_read_unlock(brmgr->local_lock); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_routemgr_local_pack(blade_routemgr_t *brmgr, cJSON *json, const char *key) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(brmgr); - ks_assert(json); - ks_assert(key); - - ks_rwl_read_lock(brmgr->local_lock); - - if (brmgr->local_nodeid) { - ret = KS_TRUE; - cJSON_AddStringToObject(json, key, brmgr->local_nodeid); - } - - ks_rwl_read_unlock(brmgr->local_lock); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_routemgr_master_set(blade_routemgr_t *brmgr, const char *nodeid) -{ - ks_assert(brmgr); - - ks_rwl_write_lock(brmgr->master_lock); - - if (brmgr->master_nodeid) ks_pool_free(&brmgr->master_nodeid); - if (nodeid) brmgr->master_nodeid = ks_pstrdup(ks_pool_get(brmgr), nodeid); - - ks_rwl_write_unlock(brmgr->master_lock); - - ks_log(KS_LOG_DEBUG, "Master NodeID: %s\n", nodeid); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_bool_t) blade_routemgr_master_check(blade_routemgr_t *brmgr, const char *target) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(brmgr); - ks_assert(target); - - ks_rwl_read_lock(brmgr->master_lock); - - ret = ks_safe_strcasecmp(brmgr->master_nodeid, target) == 0; - - // @todo may also need to check against master identities, there are a number of ways master identities - // could be propagated to ensure this check works for identities, but for now just assume that master cannot - // use identities for these checks which should generally only be done to validate certain blade CoreRPC's which - // expect the responder to be the master, and which get packed in the function below - // the following would only work on the master itself, where it registered it's own identities and thus has the - // identities in the identities mapping, other nodes do not see master identity registrations and cannot currently - // validate master identities - //if (!ret) { - // const char *nodeid = (const char *)ks_hash_search(brmgr->identities, (void *)target, KS_READLOCKED); - // ret = nodeid && !ks_safe_strcasecmp(nodeid, brmgr->master_nodeid); - // ks_hash_read_unlock(brmgr->identities); - //} - - ks_rwl_read_unlock(brmgr->master_lock); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_routemgr_master_pack(blade_routemgr_t *brmgr, cJSON *json, const char *key) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(brmgr); - ks_assert(json); - ks_assert(key); - - ks_rwl_read_lock(brmgr->master_lock); - - if (brmgr->master_nodeid) { - ret = KS_TRUE; - cJSON_AddStringToObject(json, key, brmgr->master_nodeid); - // @todo may need to pack master identities into the json as well, for now just use nodeid only and - // assume master nodes have no identities, however this call is primarily used only to force certain - // blade CoreRPC's to route to the known master node, but is also used to pass to downstream nodes - // when they connect - } - - ks_rwl_read_unlock(brmgr->master_lock); - - return ret; -} - -KS_DECLARE(ks_bool_t) blade_routemgr_master_local(blade_routemgr_t *brmgr) -{ - ks_bool_t ret = KS_FALSE; - - ks_assert(brmgr); - - ks_rwl_read_lock(brmgr->master_lock); - - ret = brmgr->master_nodeid && brmgr->local_nodeid && !ks_safe_strcasecmp(brmgr->master_nodeid, brmgr->local_nodeid); - - //ret = brmgr->master_nodeid && brmgr->localid && !ks_safe_strcasecmp(brmgr->master_nodeid, brmgr->local_nodeid); - - ks_rwl_read_unlock(brmgr->master_lock); - - return ret; -} - -KS_DECLARE(blade_session_t *) blade_routemgr_route_lookup(blade_routemgr_t *brmgr, const char *target) -{ - blade_session_t *bs = NULL; - const char *router = NULL; - - ks_assert(brmgr); - ks_assert(target); - - // Short circuit any nodeid or identity that matches the local node by returning the loopback session explicitly - // @todo this could be potentially be avoided if the local nodeid and all local identities are added as routes to the loopback sessionid - if (blade_routemgr_local_check(brmgr, target)) bs = blade_sessionmgr_loopback_lookup(blade_handle_sessionmgr_get(brmgr->handle)); - else { - // If the target is a downstream nodeid then it will be found in the route table immediately and return the sessionid of the downstream session to route through - router = (const char *)ks_hash_search(brmgr->routes, (void *)target, KS_READLOCKED); - if (!router) { - // If the target is a downstream node identity then it will be found in the identity table and return the nodeid which can then be used to lookup the route - blade_identity_t *identity = NULL; - ks_pool_t *pool = ks_pool_get(brmgr); - - blade_identity_create(&identity, pool); - if (blade_identity_parse(identity, target) == KS_STATUS_SUCCESS) { - char *key = ks_psprintf(pool, "%s@%s/%s", blade_identity_user_get(identity), blade_identity_host_get(identity), blade_identity_path_get(identity)); - - router = (const char *)ks_hash_search(brmgr->identities, (void *)key, KS_READLOCKED); - ks_hash_read_unlock(brmgr->identities); - - ks_pool_free(&key); - - if (router) router = (const char *)ks_hash_search(brmgr->routes, (void *)router, KS_UNLOCKED); - } - - blade_identity_destroy(&identity); - } - // When a router is found it is the sessionid of the downstream session, lookup the session to route through - if (router) bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(brmgr->handle), router); - ks_hash_read_unlock(brmgr->routes); - } - - return bs; -} - -ks_status_t blade_routemgr_purge(blade_routemgr_t *brmgr, const char *target) -{ - ks_hash_t* cleanup = NULL; - - ks_assert(brmgr); - ks_assert(target); - - // @note this approach is deliberately slower than it could be, as it ensures that if there is a race condition and another session has registered - // the same identity before a prior session times out, then the correct targetted random nodeid is matched to confirm the identity removal and will - // not remove if the target isn't what is expected - - ks_hash_write_lock(brmgr->identities); - - for (ks_hash_iterator_t *it = ks_hash_first(brmgr->identities, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key = NULL; - const char *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - if (value && !ks_safe_strcasecmp(value, target)) { - if (!cleanup) ks_hash_create(&cleanup, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, ks_pool_get(brmgr)); - ks_hash_insert(cleanup, (void *)key, (void *)value); - } - } - - if (cleanup) { - for (ks_hash_iterator_t *it = ks_hash_first(cleanup, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key = NULL; - const char *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - ks_log(KS_LOG_DEBUG, "Identity Removed: %s through %s\n", key, value); - - ks_hash_remove(brmgr->identities, (void *)key); - } - } - - ks_hash_write_unlock(brmgr->identities); - - if (cleanup) ks_hash_destroy(&cleanup); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_routemgr_route_add(blade_routemgr_t *brmgr, const char *target, const char *router) -{ - ks_pool_t *pool = NULL; - char *key = NULL; - char *value = NULL; - - ks_assert(brmgr); - ks_assert(target); - ks_assert(router); - - pool = ks_pool_get(brmgr); - - key = ks_pstrdup(pool, target); - value = ks_pstrdup(pool, router); - - ks_hash_insert(brmgr->routes, (void *)key, (void *)value); - - ks_log(KS_LOG_DEBUG, "Route Added: %s through %s\n", key, value); - - blade_handle_rpcroute(brmgr->handle, target, KS_FALSE, NULL, NULL); - - if (blade_routemgr_master_local(brmgr)) { - cJSON *params = cJSON_CreateObject(); - cJSON_AddStringToObject(params, "nodeid", target); - blade_subscriptionmgr_broadcast(blade_handle_subscriptionmgr_get(brmgr->handle), BLADE_RPCBROADCAST_COMMAND_EVENT, NULL, "blade.presence", "join", "joined", params, NULL, NULL); - cJSON_Delete(params); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_routemgr_route_remove(blade_routemgr_t *brmgr, const char *target) -{ - ks_assert(brmgr); - ks_assert(target); - - ks_hash_remove(brmgr->routes, (void *)target); - - ks_log(KS_LOG_DEBUG, "Route Removed: %s\n", target); - - blade_handle_rpcroute(brmgr->handle, target, KS_TRUE, NULL, NULL); - - blade_subscriptionmgr_purge(blade_handle_subscriptionmgr_get(brmgr->handle), target); - - // @note protocols are cleaned up here because routes can be removed that are not locally connected with a session but still - // have protocols published to the master node from further downstream, in which case if a route is announced upstream to be - // removed, a master node is still able to catch that here even when there is no direct session, but is also hit when there - // is a direct session being terminated - - blade_mastermgr_purge(blade_handle_mastermgr_get(brmgr->handle), target); - - blade_routemgr_purge(brmgr, target); - - if (blade_routemgr_master_local(brmgr)) { - cJSON *params = cJSON_CreateObject(); - cJSON_AddStringToObject(params, "nodeid", target); - blade_subscriptionmgr_broadcast(blade_handle_subscriptionmgr_get(brmgr->handle), BLADE_RPCBROADCAST_COMMAND_EVENT, NULL, "blade.presence", "leave", "left", params, NULL, NULL); - cJSON_Delete(params); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_routemgr_identity_add(blade_routemgr_t *brmgr, blade_identity_t *identity, const char *target) -{ - ks_pool_t *pool = NULL; - char *key = NULL; - char *value = NULL; - - ks_assert(brmgr); - ks_assert(identity); - ks_assert(target); - - pool = ks_pool_get(brmgr); - - key = ks_psprintf(pool, "%s@%s/%s", blade_identity_user_get(identity), blade_identity_host_get(identity), blade_identity_path_get(identity)); - value = ks_pstrdup(pool, target); - - ks_hash_insert(brmgr->identities, (void *)key, (void *)value); - - ks_log(KS_LOG_DEBUG, "Identity Added: %s through %s\n", key, value); - - //if (blade_routemgr_master_local(blade_handle_routemgr_get(brmgr->handle))) { - // cJSON *params = cJSON_CreateObject(); - // cJSON_AddStringToObject(params, "identity", blade_identity_uri_get(identity)); // full identity uri string - // cJSON_AddStringToObject(params, "nodeid", target); - // blade_subscriptionmgr_broadcast(blade_handle_subscriptionmgr_get(brmgr->handle), BLADE_RPCBROADCAST_COMMAND_EVENT, NULL, "blade.presence", "join", "joined", params, NULL, NULL); - // cJSON_Delete(params); - //} - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_routemgr_identity_remove(blade_routemgr_t *brmgr, blade_identity_t *identity, const char *target) -{ - ks_pool_t *pool = NULL; - char *key = NULL; - const char *value = NULL; - - ks_assert(brmgr); - ks_assert(identity); - ks_assert(target); - - pool = ks_pool_get(brmgr); - - key = ks_psprintf(pool, "%s@%s/%s", blade_identity_user_get(identity), blade_identity_host_get(identity), blade_identity_path_get(identity)); - - // @note this approach is deliberately slower than it could be, as it ensures that if there is a race condition and another session has registered - // the same identity before a prior session times out, then the correct targetted random nodeid is matched to confirm the identity removal and will - // not remove if the target isn't what is expected - - ks_hash_write_lock(brmgr->identities); - - value = (const char *)ks_hash_search(brmgr->identities, (void *)key, KS_UNLOCKED); - - if (value && !ks_safe_strcasecmp(value, target)) { - ks_hash_remove(brmgr->identities, (void *)key); - - ks_log(KS_LOG_DEBUG, "Identity Removed: %s through %s\n", key, value); - } - - ks_hash_write_unlock(brmgr->identities); - - //if (blade_routemgr_master_local(blade_handle_routemgr_get(brmgr->handle))) { - // cJSON *params = cJSON_CreateObject(); - // cJSON_AddStringToObject(params, "nodeid", target); - // blade_subscriptionmgr_broadcast(blade_handle_subscriptionmgr_get(brmgr->handle), BLADE_RPCBROADCAST_COMMAND_EVENT, NULL, "blade.presence", "leave", "left", params, NULL, NULL); - // cJSON_Delete(params); - //} - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_rpc.c b/libs/libblade/src/blade_rpc.c deleted file mode 100644 index cfc0e78ce5..0000000000 --- a/libs/libblade/src/blade_rpc.c +++ /dev/null @@ -1,460 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_rpc_s { - blade_handle_t *handle; - - const char *method; - const char *protocol; - - blade_rpc_request_callback_t callback; - void *data; -}; - -struct blade_rpc_request_s { - blade_handle_t *handle; - - const char *session_id; - - cJSON *message; - const char *message_id; // pulled from message for easier keying - - ks_time_t ttl; - - blade_rpc_response_callback_t callback; - void *data; -}; - -struct blade_rpc_response_s { - blade_handle_t *handle; - - const char *session_id; - - blade_rpc_request_t *request; - - cJSON *message; -}; - - -static void blade_rpc_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_rpc_t *brpc = (blade_rpc_t *)ptr; - - //ks_assert(brpc); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - // @todo delete data if present, requires update to ks_pool for self tracking the pool in allocation header - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_rpc_create(blade_rpc_t **brpcP, blade_handle_t *bh, const char *method, const char *protocol, blade_rpc_request_callback_t callback, void *data) -{ - blade_rpc_t *brpc = NULL; - ks_pool_t *pool = NULL; - - ks_assert(brpcP); - ks_assert(bh); - ks_assert(method); - ks_assert(callback); - - ks_pool_open(&pool); - ks_assert(pool); - - brpc = ks_pool_alloc(pool, sizeof(blade_rpc_t)); - brpc->handle = bh; - brpc->method = ks_pstrdup(pool, method); - if (protocol) brpc->protocol = ks_pstrdup(pool, protocol); - brpc->callback = callback; - brpc->data = data; - - ks_pool_set_cleanup(brpc, NULL, blade_rpc_cleanup); - - *brpcP = brpc; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_rpc_destroy(blade_rpc_t **brpcP) -{ - blade_rpc_t *brpc = NULL; - ks_pool_t *pool = NULL; - - ks_assert(brpcP); - ks_assert(*brpcP); - - brpc = *brpcP; - *brpcP = NULL; - - pool = ks_pool_get(brpc); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_rpc_handle_get(blade_rpc_t *brpc) -{ - ks_assert(brpc); - - return brpc->handle; -} - -KS_DECLARE(const char *) blade_rpc_method_get(blade_rpc_t *brpc) -{ - ks_assert(brpc); - - return brpc->method; -} - -KS_DECLARE(const char *) blade_rpc_protocol_get(blade_rpc_t *brpc) -{ - ks_assert(brpc); - - return brpc->protocol; -} - -KS_DECLARE(blade_rpc_request_callback_t) blade_rpc_callback_get(blade_rpc_t *brpc) -{ - ks_assert(brpc); - - return brpc->callback; -} - -KS_DECLARE(void *) blade_rpc_data_get(blade_rpc_t *brpc) -{ - ks_assert(brpc); - - return brpc->data; -} - - -static void blade_rpc_request_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_rpc_request_t *brpcreq = (blade_rpc_request_t *)ptr; - - ks_assert(brpcreq); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - ks_pool_free((void **)&brpcreq->session_id); - cJSON_Delete(brpcreq->message); - // @todo delete data if present, requires update to ks_pool for self tracking the pool in allocation header - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_rpc_request_create(blade_rpc_request_t **brpcreqP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - cJSON *json, - blade_rpc_response_callback_t callback, - void *data) -{ - blade_rpc_request_t *brpcreq = NULL; - - ks_assert(brpcreqP); - ks_assert(bh); - ks_assert(pool); - ks_assert(session_id); - ks_assert(json); - - brpcreq = ks_pool_alloc(pool, sizeof(blade_rpc_request_t)); - brpcreq->handle = bh; - brpcreq->session_id = ks_pstrdup(pool, session_id); - brpcreq->message = cJSON_Duplicate(json, 1); - brpcreq->message_id = cJSON_GetObjectCstr(brpcreq->message, "id"); - brpcreq->callback = callback; - brpcreq->data = data; - - ks_pool_set_cleanup(brpcreq, NULL, blade_rpc_request_cleanup); - - *brpcreqP = brpcreq; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_rpc_request_destroy(blade_rpc_request_t **brpcreqP) -{ - ks_assert(brpcreqP); - ks_assert(*brpcreqP); - - ks_pool_free(brpcreqP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_rpc_request_duplicate(blade_rpc_request_t **brpcreqP, blade_rpc_request_t *brpcreq) -{ - return blade_rpc_request_create(brpcreqP, brpcreq->handle, ks_pool_get(brpcreq), brpcreq->session_id, brpcreq->message, brpcreq->callback, brpcreq->data); -} - -KS_DECLARE(blade_handle_t *) blade_rpc_request_handle_get(blade_rpc_request_t *brpcreq) -{ - ks_assert(brpcreq); - return brpcreq->handle; -} - -KS_DECLARE(const char *) blade_rpc_request_sessionid_get(blade_rpc_request_t *brpcreq) -{ - ks_assert(brpcreq); - return brpcreq->session_id; -} - -KS_DECLARE(cJSON *) blade_rpc_request_message_get(blade_rpc_request_t *brpcreq) -{ - ks_assert(brpcreq); - return brpcreq->message; -} - -KS_DECLARE(const char *) blade_rpc_request_messageid_get(blade_rpc_request_t *brpcreq) -{ - ks_assert(brpcreq); - return brpcreq->message_id; -} - -KS_DECLARE(ks_status_t) blade_rpc_request_ttl_set(blade_rpc_request_t *brpcreq, ks_time_t ttl) -{ - ks_assert(brpcreq); - - brpcreq->ttl = ks_time_now() + (ttl * KS_USEC_PER_SEC); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_bool_t) blade_rpc_request_expired(blade_rpc_request_t *brpcreq) -{ - ks_assert(brpcreq); - - return brpcreq->ttl <= ks_time_now(); -} - -KS_DECLARE(blade_rpc_response_callback_t) blade_rpc_request_callback_get(blade_rpc_request_t *brpcreq) -{ - ks_assert(brpcreq); - return brpcreq->callback; -} - -KS_DECLARE(void *) blade_rpc_request_data_get(blade_rpc_request_t *brpcreq) -{ - ks_assert(brpcreq); - return brpcreq->data; -} - -KS_DECLARE(ks_status_t) blade_rpc_request_raw_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method) -{ - cJSON *root = NULL; - cJSON *p = NULL; - uuid_t msgid; - const char *mid = NULL; - - ks_assert(pool); - ks_assert(json); - ks_assert(method); - - root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "jsonrpc", "2.0"); - - ks_uuid(&msgid); - mid = ks_uuid_str(pool, &msgid); - cJSON_AddStringToObject(root, "id", mid); - ks_pool_free(&mid); - - cJSON_AddStringToObject(root, "method", method); - - p = cJSON_CreateObject(); - cJSON_AddItemToObject(root, "params", p); - - *json = root; - if (params) *params = p; - if (id) *id = cJSON_GetObjectCstr(root, "id"); - - return KS_STATUS_SUCCESS; -} - - -static void blade_rpc_response_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_rpc_response_t *brpcres = (blade_rpc_response_t *)ptr; - - ks_assert(brpcres); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - ks_pool_free((void **)&brpcres->session_id); - blade_rpc_request_destroy(&brpcres->request); - cJSON_Delete(brpcres->message); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_rpc_response_create(blade_rpc_response_t **brpcresP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - blade_rpc_request_t *brpcreq, - cJSON *json) -{ - blade_rpc_response_t *brpcres = NULL; - - ks_assert(brpcresP); - ks_assert(bh); - ks_assert(pool); - ks_assert(session_id); - ks_assert(brpcreq); - ks_assert(json); - - brpcres = ks_pool_alloc(pool, sizeof(blade_rpc_response_t)); - brpcres->handle = bh; - brpcres->session_id = ks_pstrdup(pool, session_id); - brpcres->request = brpcreq; - brpcres->message = cJSON_Duplicate(json, 1); - - ks_pool_set_cleanup(brpcres, NULL, blade_rpc_response_cleanup); - - *brpcresP = brpcres; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_rpc_response_destroy(blade_rpc_response_t **brpcresP) -{ - ks_assert(brpcresP); - ks_assert(*brpcresP); - - ks_pool_free(brpcresP); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(ks_status_t) blade_rpc_response_raw_create(cJSON **json, cJSON **result, const char *id) -{ - cJSON *root = NULL; - cJSON *r = NULL; - - ks_assert(json); - ks_assert(id); - - root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "jsonrpc", "2.0"); - - cJSON_AddStringToObject(root, "id", id); - - r = cJSON_CreateObject(); - cJSON_AddItemToObject(root, "result", r); - - *json = root; - if (result) *result = r; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_rpc_response_handle_get(blade_rpc_response_t *brpcres) -{ - ks_assert(brpcres); - return brpcres->handle; -} - -KS_DECLARE(const char *) blade_rpc_response_sessionid_get(blade_rpc_response_t *brpcres) -{ - ks_assert(brpcres); - return brpcres->session_id; -} - -KS_DECLARE(blade_rpc_request_t *) blade_rpc_response_request_get(blade_rpc_response_t *brpcres) -{ - ks_assert(brpcres); - return brpcres->request; -} - -KS_DECLARE(cJSON *) blade_rpc_response_message_get(blade_rpc_response_t *brpcres) -{ - ks_assert(brpcres); - return brpcres->message; -} - -KS_DECLARE(ks_status_t) blade_rpc_error_raw_create(cJSON **json, cJSON **error, const char *id, int32_t code, const char *message) -{ - cJSON *root = NULL; - cJSON *e = NULL; - - ks_assert(json); - //ks_assert(id); - ks_assert(message); - - root = cJSON_CreateObject(); - - cJSON_AddStringToObject(root, "jsonrpc", "2.0"); - - if (id) cJSON_AddStringToObject(root, "id", id); - - e = cJSON_CreateObject(); - cJSON_AddNumberToObject(e, "code", code); - cJSON_AddStringToObject(e, "message", message); - cJSON_AddItemToObject(root, "error", e); - - *json = root; - if (error) *error = e; - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_rpcmgr.c b/libs/libblade/src/blade_rpcmgr.c deleted file mode 100644 index 21b91c3335..0000000000 --- a/libs/libblade/src/blade_rpcmgr.c +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_rpcmgr_s { - blade_handle_t *handle; - - ks_hash_t *corerpcs; // method, blade_rpc_t* - ks_hash_t *protocolrpcs; // method, blade_rpc_t* - - ks_hash_t *requests; // id, blade_rpc_request_t* - ks_time_t requests_ttlcheck; - ks_mutex_t* requests_ttlcheck_lock; -}; - - -static void blade_rpcmgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_rpcmgr_t *brpcmgr = (blade_rpcmgr_t *)ptr; - ks_hash_iterator_t *it = NULL; - - ks_assert(brpcmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - while ((it = ks_hash_first(brpcmgr->protocolrpcs, KS_UNLOCKED)) != NULL) { - void *key = NULL; - blade_rpc_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - ks_hash_remove(brpcmgr->protocolrpcs, key); - - blade_rpc_destroy(&value); // must call destroy to close the method pool, using FREE_VALUE on the hash would attempt to free the method from the wrong pool - } - while ((it = ks_hash_first(brpcmgr->corerpcs, KS_UNLOCKED)) != NULL) { - void *key = NULL; - blade_rpc_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - ks_hash_remove(brpcmgr->corerpcs, key); - - blade_rpc_destroy(&value); // must call destroy to close the rpc pool, using FREE_VALUE on the hash would attempt to free the rpc from the wrong pool - } - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_create(blade_rpcmgr_t **brpcmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_rpcmgr_t *brpcmgr = NULL; - - ks_assert(brpcmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - brpcmgr = ks_pool_alloc(pool, sizeof(blade_rpcmgr_t)); - brpcmgr->handle = bh; - - ks_hash_create(&brpcmgr->corerpcs, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(brpcmgr->corerpcs); - - ks_hash_create(&brpcmgr->protocolrpcs, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(brpcmgr->protocolrpcs); - - ks_hash_create(&brpcmgr->requests, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(brpcmgr->requests); - - ks_mutex_create(&brpcmgr->requests_ttlcheck_lock, KS_MUTEX_FLAG_NON_RECURSIVE, pool); - ks_assert(brpcmgr->requests_ttlcheck_lock); - - ks_pool_set_cleanup(brpcmgr, NULL, blade_rpcmgr_cleanup); - - *brpcmgrP = brpcmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_destroy(blade_rpcmgr_t **brpcmgrP) -{ - blade_rpcmgr_t *brpcmgr = NULL; - ks_pool_t *pool; - - ks_assert(brpcmgrP); - ks_assert(*brpcmgrP); - - brpcmgr = *brpcmgrP; - *brpcmgrP = NULL; - - pool = ks_pool_get(brpcmgr); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_rpcmgr_handle_get(blade_rpcmgr_t *brpcmgr) -{ - ks_assert(brpcmgr); - - return brpcmgr->handle; -} - -KS_DECLARE(blade_rpc_t *) blade_rpcmgr_corerpc_lookup(blade_rpcmgr_t *brpcmgr, const char *method) -{ - blade_rpc_t *brpc = NULL; - - ks_assert(brpcmgr); - ks_assert(method); - - brpc = (blade_rpc_t *)ks_hash_search(brpcmgr->corerpcs, (void *)method, KS_READLOCKED); - // @todo if (brpc) blade_rpc_read_lock(brpc); - ks_hash_read_unlock(brpcmgr->corerpcs); - - return brpc; -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_corerpc_add(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc) -{ - char *key = NULL; - - ks_assert(brpcmgr); - ks_assert(brpc); - - key = ks_pstrdup(ks_pool_get(brpcmgr), blade_rpc_method_get(brpc)); - ks_hash_insert(brpcmgr->corerpcs, (void *)key, (void *)brpc); - - ks_log(KS_LOG_DEBUG, "CoreRPC Added: %s\n", key); - - return KS_STATUS_SUCCESS; - -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_corerpc_remove(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc) -{ - const char *method = NULL; - - ks_assert(brpcmgr); - ks_assert(brpc); - - method = blade_rpc_method_get(brpc); - ks_hash_remove(brpcmgr->corerpcs, (void *)method); - - ks_log(KS_LOG_DEBUG, "CoreRPC Removed: %s\n", method); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_rpc_t *) blade_rpcmgr_protocolrpc_lookup(blade_rpcmgr_t *brpcmgr, const char *method, const char *protocol) -{ - blade_rpc_t *brpc = NULL; - char *key = NULL; - - ks_assert(brpcmgr); - ks_assert(method); - ks_assert(protocol); - - key = ks_psprintf(ks_pool_get(brpcmgr), "%s:%s", protocol, method); - brpc = ks_hash_search(brpcmgr->protocolrpcs, (void *)key, KS_READLOCKED); - // @todo if (brpc) blade_rpc_read_lock(brpc); - ks_hash_read_unlock(brpcmgr->protocolrpcs); - - ks_pool_free(&key); - - return brpc; -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_protocolrpc_add(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc) -{ - const char *method = NULL; - const char *protocol = NULL; - char *key = NULL; - - ks_assert(brpcmgr); - ks_assert(brpc); - - method = blade_rpc_method_get(brpc); - ks_assert(method); - - protocol = blade_rpc_protocol_get(brpc); - ks_assert(protocol); - - key = ks_psprintf(ks_pool_get(brpcmgr), "%s:%s", protocol, method); - ks_assert(key); - - ks_hash_insert(brpcmgr->protocolrpcs, (void *)key, (void *)brpc); - - ks_log(KS_LOG_DEBUG, "ProtocolRPC Added: %s\n", key); - -return KS_STATUS_SUCCESS; - -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_protocolrpc_remove(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc) -{ - const char *method = NULL; - const char *protocol = NULL; - char *key = NULL; - - ks_assert(brpcmgr); - ks_assert(brpc); - - method = blade_rpc_method_get(brpc); - ks_assert(method); - - protocol = blade_rpc_protocol_get(brpc); - ks_assert(protocol); - - key = ks_psprintf(ks_pool_get(brpcmgr), "%s:%s", protocol, method); - ks_assert(key); - - ks_hash_remove(brpcmgr->protocolrpcs, (void *)key); - - ks_log(KS_LOG_DEBUG, "ProtocolRPC Removed: %s\n", key); - - ks_pool_free(&key); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_rpc_request_t *) blade_rpcmgr_request_lookup(blade_rpcmgr_t *brpcmgr, const char *id) -{ - blade_rpc_request_t *brpcreq = NULL; - - ks_assert(brpcmgr); - ks_assert(id); - - brpcreq = (blade_rpc_request_t *)ks_hash_search(brpcmgr->requests, (void *)id, KS_READLOCKED); - // @todo if (brpcreq) blade_rpc_request_read_lock(brpcreq); - ks_hash_read_unlock(brpcmgr->requests); - - return brpcreq; -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_request_add(blade_rpcmgr_t *brpcmgr, blade_rpc_request_t *brpcreq) -{ - char *key = NULL; - - ks_assert(brpcmgr); - ks_assert(brpcreq); - - key = ks_pstrdup(ks_pool_get(brpcmgr), blade_rpc_request_messageid_get(brpcreq)); - ks_hash_insert(brpcmgr->requests, (void *)key, (void *)brpcreq); - - ks_log(KS_LOG_DEBUG, "Request Added: %s\n", key); - - return KS_STATUS_SUCCESS; - -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_request_remove(blade_rpcmgr_t *brpcmgr, blade_rpc_request_t *brpcreq) -{ - const char *id = NULL; - - ks_assert(brpcmgr); - ks_assert(brpcreq); - - id = blade_rpc_request_messageid_get(brpcreq); - ks_hash_remove(brpcmgr->requests, (void *)id); - - ks_log(KS_LOG_DEBUG, "Request Removed: %s\n", id); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_rpcmgr_request_timeouts(blade_rpcmgr_t *brpcmgr) -{ - blade_session_t *loopback = NULL; - - ks_assert(brpcmgr); - - // All this stuff is to ensure that the requests hash is not locked up when it does not need to be, - // and this will also ensure that sessions will not lock up if any other session is trying to deal - // with timeouts already - if (ks_mutex_trylock(brpcmgr->requests_ttlcheck_lock) != KS_STATUS_SUCCESS) return KS_STATUS_SUCCESS; - - if (brpcmgr->requests_ttlcheck > ks_time_now()) { - ks_mutex_unlock(brpcmgr->requests_ttlcheck_lock); - return KS_STATUS_SUCCESS; - } - - ks_hash_write_lock(brpcmgr->requests); - - // Give a one second delay between timeout checking - brpcmgr->requests_ttlcheck = ks_time_now() + KS_USEC_PER_SEC; - - ks_mutex_unlock(brpcmgr->requests_ttlcheck_lock); - - // Now find all the expired requests and send out loopback error responses, which will invoke request removal when received and processed - for (ks_hash_iterator_t *it = ks_hash_first(brpcmgr->requests, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key = NULL; - blade_rpc_request_t *value = NULL; - cJSON *res = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - if (!blade_rpc_request_expired(value)) continue; - - if (!loopback) loopback = blade_sessionmgr_loopback_lookup(blade_handle_sessionmgr_get(brpcmgr->handle)); - - ks_log(KS_LOG_DEBUG, "Request (%s) TTL timeout\n", key); - - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(value), -32000, "Request timed out"); - // @todo may want to include requester-nodeid and responder-nodeid into the error block when they are present in the original request - // even though a response or error without them is treated as locally processed, it may be useful to know who the request was attempted with - // when multiple options are available such as a blade.execute where the protocol has multiple possible controllers to pick from - blade_session_send(loopback, res, 0, NULL, NULL); - - cJSON_Delete(res); - } - - if (loopback) blade_session_read_unlock(loopback); - - ks_hash_write_unlock(brpcmgr->requests); - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_session.c b/libs/libblade/src/blade_session.c deleted file mode 100644 index 0e50b90f64..0000000000 --- a/libs/libblade/src/blade_session.c +++ /dev/null @@ -1,810 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_session_s { - blade_handle_t *handle; - - blade_session_flags_t flags; - - const char *id; - ks_rwl_t *lock; - - volatile blade_session_state_t state; - - ks_cond_t *cond; - - const char *connection; - ks_time_t ttl; - - ks_q_t *sending; - ks_q_t *receiving; - - ks_hash_t *routes; - - cJSON *properties; - ks_rwl_t *properties_lock; -}; - -void *blade_session_state_thread(ks_thread_t *thread, void *data); -ks_status_t blade_session_onstate_startup(blade_session_t *bs); -ks_status_t blade_session_onstate_shutdown(blade_session_t *bs); -ks_status_t blade_session_onstate_run(blade_session_t *bs); -ks_status_t blade_session_process(blade_session_t *bs, cJSON *json); - -static void blade_session_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_session_t *bs = (blade_session_t *)ptr; - - ks_assert(bs); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - blade_session_shutdown(bs); - break; - case KS_MPCL_DESTROY: - // @todo consider looking at supporting externally allocated memory entries that can have cleanup callbacks associated, but the memory is not freed from the pool, only linked as an external allocation for auto cleanup - // which would allow calling something like ks_pool_set_cleanup(bs->properties, ...) and when the pool is destroyed, it can call a callback which handles calling cJSON_Delete, which is allocated externally - cJSON_Delete(bs->properties); - break; - } -} - - -KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle_t *bh, blade_session_flags_t flags, const char *sessionid) -{ - blade_session_t *bs = NULL; - ks_pool_t *pool = NULL; - - ks_assert(bsP); - ks_assert(bh); - - ks_pool_open(&pool); - ks_assert(pool); - - bs = ks_pool_alloc(pool, sizeof(blade_session_t)); - bs->handle = bh; - bs->flags = flags; - - if (sessionid) bs->id = ks_pstrdup(pool, sessionid); - else { - uuid_t id; - ks_uuid(&id); - bs->id = ks_uuid_str(pool, &id); - } - - ks_rwl_create(&bs->lock, pool); - ks_assert(bs->lock); - - bs->state = BLADE_SESSION_STATE_NONE; - - ks_cond_create(&bs->cond, pool); - ks_assert(bs->cond); - - ks_q_create(&bs->sending, pool, 0); - ks_assert(bs->sending); - ks_q_create(&bs->receiving, pool, 0); - ks_assert(bs->receiving); - - ks_hash_create(&bs->routes, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bs->routes); - - bs->properties = cJSON_CreateObject(); - ks_assert(bs->properties); - ks_rwl_create(&bs->properties_lock, pool); - ks_assert(bs->properties_lock); - - ks_pool_set_cleanup(bs, NULL, blade_session_cleanup); - - ks_log(KS_LOG_DEBUG, "Created\n"); - - *bsP = bs; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_session_destroy(blade_session_t **bsP) -{ - blade_session_t *bs = NULL; - ks_pool_t *pool = NULL; - - ks_assert(bsP); - ks_assert(*bsP); - - bs = *bsP; - *bsP = NULL; - - pool = ks_pool_get(bs); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_session_startup(blade_session_t *bs) -{ - ks_thread_pool_t *tpool = NULL; - - ks_assert(bs); - - tpool = blade_handle_tpool_get(bs->handle); - ks_assert(tpool); - - if (ks_thread_pool_add_job(tpool, blade_session_state_thread, bs) != KS_STATUS_SUCCESS) { - // @todo error logging - return KS_STATUS_FAIL; - } - - ks_log(KS_LOG_DEBUG, "Started\n"); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_session_shutdown(blade_session_t *bs) -{ - ks_hash_iterator_t *it = NULL; - cJSON *json = NULL; - - ks_assert(bs); - - // make sure this is done first to remove the upstream session before it is attempted to be used for sending route updates - blade_sessionmgr_session_remove(blade_handle_sessionmgr_get(bs->handle), bs); - - // if this is an upstream session there will be no routes, so this is harmless to always run regardless - ks_hash_read_lock(bs->routes); - for (it = ks_hash_first(bs->routes, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - - blade_routemgr_route_remove(blade_handle_routemgr_get(bs->handle), (const char *)key); - } - ks_hash_read_unlock(bs->routes); - - while (ks_q_trypop(bs->sending, (void **)&json) == KS_STATUS_SUCCESS && json) cJSON_Delete(json); - while (ks_q_trypop(bs->receiving, (void **)&json) == KS_STATUS_SUCCESS && json) cJSON_Delete(json); - - ks_log(KS_LOG_DEBUG, "Stopped\n"); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_session_handle_get(blade_session_t *bs) -{ - ks_assert(bs); - - return bs->handle; -} - -KS_DECLARE(ks_bool_t) blade_session_loopback(blade_session_t *bs) -{ - ks_assert(bs); - return (bs->flags & BLADE_SESSION_FLAGS_LOOPBACK) == BLADE_SESSION_FLAGS_LOOPBACK; -} - -KS_DECLARE(ks_bool_t) blade_session_upstream(blade_session_t *bs) -{ - ks_assert(bs); - return (bs->flags & BLADE_SESSION_FLAGS_UPSTREAM) == BLADE_SESSION_FLAGS_UPSTREAM; -} - -KS_DECLARE(const char *) blade_session_id_get(blade_session_t *bs) -{ - ks_assert(bs); - - return bs->id; -} - -KS_DECLARE(blade_session_state_t) blade_session_state_get(blade_session_t *bs) -{ - ks_assert(bs); - - return bs->state; -} - -KS_DECLARE(ks_status_t) blade_session_route_add(blade_session_t *bs, const char *nodeid) -{ - char *key = NULL; - - ks_assert(bs); - ks_assert(nodeid); - - key = ks_pstrdup(ks_pool_get(bs), nodeid); - ks_hash_insert(bs->routes, (void *)key, (void *)KS_TRUE); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_session_route_remove(blade_session_t *bs, const char *nodeid) -{ - ks_assert(bs); - ks_assert(nodeid); - - ks_hash_remove(bs->routes, (void *)nodeid); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(cJSON *) blade_session_properties_get(blade_session_t *bs) -{ - ks_assert(bs); - - return bs->properties; -} - -KS_DECLARE(ks_status_t) blade_session_read_lock(blade_session_t *bs, ks_bool_t block) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(bs); - - if (block) ret = ks_rwl_read_lock(bs->lock); - else ret = ks_rwl_try_read_lock(bs->lock); - return ret; -} - -KS_DECLARE(ks_status_t) blade_session_read_unlock(blade_session_t *bs) -{ - ks_assert(bs); - - return ks_rwl_read_unlock(bs->lock); -} - -KS_DECLARE(ks_status_t) blade_session_write_lock(blade_session_t *bs, ks_bool_t block) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(bs); - - if (block) ret = ks_rwl_write_lock(bs->lock); - else ret = ks_rwl_try_write_lock(bs->lock); - return ret; -} - -KS_DECLARE(ks_status_t) blade_session_write_unlock(blade_session_t *bs) -{ - ks_assert(bs); - - return ks_rwl_write_unlock(bs->lock); -} - - -KS_DECLARE(ks_status_t) blade_session_properties_read_lock(blade_session_t *bs, ks_bool_t block) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(bs); - - if (block) ret = ks_rwl_read_lock(bs->properties_lock); - else ret = ks_rwl_try_read_lock(bs->properties_lock); - return ret; -} - -KS_DECLARE(ks_status_t) blade_session_properties_read_unlock(blade_session_t *bs) -{ - ks_assert(bs); - - return ks_rwl_read_unlock(bs->properties_lock); -} - -KS_DECLARE(ks_status_t) blade_session_properties_write_lock(blade_session_t *bs, ks_bool_t block) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(bs); - - if (block) ret = ks_rwl_write_lock(bs->properties_lock); - else ret = ks_rwl_try_write_lock(bs->properties_lock); - return ret; -} - -KS_DECLARE(ks_status_t) blade_session_properties_write_unlock(blade_session_t *bs) -{ - ks_assert(bs); - - return ks_rwl_write_unlock(bs->properties_lock); -} - - -KS_DECLARE(void) blade_session_state_set(blade_session_t *bs, blade_session_state_t state) -{ - ks_assert(bs); - - ks_cond_lock(bs->cond); - bs->state = state; - blade_sessionmgr_callback_execute(blade_handle_sessionmgr_get(bs->handle), bs, BLADE_SESSION_STATE_CONDITION_PRE); - ks_cond_unlock(bs->cond); - - ks_cond_try_signal(bs->cond); -} - -KS_DECLARE(void) blade_session_hangup(blade_session_t *bs) -{ - ks_assert(bs); - - if (!blade_session_terminating(bs)) { - ks_log(KS_LOG_DEBUG, "Session (%s) hanging up\n", bs->id); - blade_session_state_set(bs, BLADE_SESSION_STATE_SHUTDOWN); - } -} - -KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs) -{ - ks_assert(bs); - - return bs->state == BLADE_SESSION_STATE_SHUTDOWN || bs->state == BLADE_SESSION_STATE_CLEANUP; -} - -KS_DECLARE(const char *) blade_session_connection_get(blade_session_t *bs) -{ - ks_assert(bs); - return bs->connection; -} - -KS_DECLARE(ks_status_t) blade_session_connection_set(blade_session_t *bs, const char *id) -{ - ks_assert(bs); - - if (id) { - if (bs->connection) { - // @todo best that can be done in this situation is see if the connection is still available, and if so then disconnect it... this really shouldn't happen - ks_pool_free(&bs->connection); - } - bs->connection = ks_pstrdup(ks_pool_get(bs), id); - ks_assert(bs->connection); - - bs->ttl = 0; - - ks_log(KS_LOG_DEBUG, "Session (%s) associated to connection (%s)\n", bs->id, id); - - // @todo signal the wait condition for the state machine to see a reconnect immediately - } else if (bs->connection) { - ks_log(KS_LOG_DEBUG, "Session (%s) cleared connection (%s)\n", bs->id, bs->connection); - - ks_pool_free(&bs->connection); - - bs->ttl = ks_time_now() + (5 * KS_USEC_PER_SEC); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_session_sending_push(blade_session_t *bs, cJSON *json) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - cJSON *json_copy = NULL; - - ks_assert(bs); - ks_assert(json); - - if ((bs->flags & BLADE_SESSION_FLAGS_LOOPBACK) == BLADE_SESSION_FLAGS_LOOPBACK) - ret = blade_session_receiving_push(bs, json); - else { - json_copy = cJSON_Duplicate(json, 1); - if ((ret = ks_q_push(bs->sending, json_copy)) == KS_STATUS_SUCCESS) ks_cond_try_signal(bs->cond); - } - return ret; -} - -KS_DECLARE(ks_status_t) blade_session_sending_pop(blade_session_t *bs, cJSON **json) -{ - ks_assert(bs); - ks_assert(json); - - return ks_q_trypop(bs->sending, (void **)json); -} - -KS_DECLARE(ks_status_t) blade_session_receiving_push(blade_session_t *bs, cJSON *json) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - cJSON *json_copy = NULL; - - ks_assert(bs); - ks_assert(json); - - json_copy = cJSON_Duplicate(json, 1); - if ((ret = ks_q_push(bs->receiving, json_copy)) == KS_STATUS_SUCCESS) ks_cond_try_signal(bs->cond); - return ret; -} - -KS_DECLARE(ks_status_t) blade_session_receiving_pop(blade_session_t *bs, cJSON **json) -{ - ks_assert(bs); - ks_assert(json); - - return ks_q_trypop(bs->receiving, (void **)json); -} - - -void *blade_session_state_thread(ks_thread_t *thread, void *data) -{ - blade_session_t *bs = NULL; - blade_session_state_t state; - cJSON *json = NULL; - ks_bool_t shutdown = KS_FALSE; - - ks_assert(thread); - ks_assert(data); - - bs = (blade_session_t *)data; - - ks_cond_lock(bs->cond); - while (!shutdown) { - // Entering the call below, the mutex is expected to be locked and will be unlocked by the call - ks_cond_timedwait(bs->cond, 100); - // Leaving the call above, the mutex will be locked after being signalled, timing out, or woken up for any reason - - state = bs->state; - - if (bs->connection) { - blade_connection_t *bc = blade_connectionmgr_connection_lookup(blade_handle_connectionmgr_get(bs->handle), bs->connection); - if (bc) { - // @note in order for this to work on session reconnecting, the assumption is that as soon as a session has a connection set, - // we can start stuffing any messages queued for output on the session straight to the connection right away, may need to only - // do this when in session ready state but there may be implications of other states sending messages through the session - while (blade_session_sending_pop(bs, &json) == KS_STATUS_SUCCESS && json) { - blade_connection_sending_push(bc, json); - cJSON_Delete(json); - } - blade_connection_read_unlock(bc); - } - } - - // @todo evolve this system, it's probably not the best way to handle receiving session state updates externally - blade_sessionmgr_callback_execute(blade_handle_sessionmgr_get(bs->handle), bs, BLADE_SESSION_STATE_CONDITION_POST); - - switch (state) { - case BLADE_SESSION_STATE_STARTUP: - blade_session_onstate_startup(bs); - break; - case BLADE_SESSION_STATE_SHUTDOWN: - blade_session_onstate_shutdown(bs); - shutdown = KS_TRUE; - break; - case BLADE_SESSION_STATE_RUN: - blade_session_onstate_run(bs); - break; - default: break; - } - - if ((bs->flags & BLADE_SESSION_FLAGS_LOOPBACK) != BLADE_SESSION_FLAGS_LOOPBACK && - !bs->connection && - bs->ttl > 0 && - !blade_session_terminating(bs) && - ks_time_now() >= bs->ttl) { - ks_log(KS_LOG_DEBUG, "Session (%s) TTL timeout\n", bs->id); - blade_session_hangup(bs); - } - } - ks_cond_unlock(bs->cond); - - blade_session_destroy(&bs); - - return NULL; -} - -ks_status_t blade_session_onstate_startup(blade_session_t *bs) -{ - ks_assert(bs); - - ks_log(KS_LOG_DEBUG, "Session (%s) state startup\n", bs->id); - blade_session_state_set(bs, BLADE_SESSION_STATE_RUN); - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_session_onstate_shutdown(blade_session_t *bs) -{ - ks_assert(bs); - - ks_log(KS_LOG_DEBUG, "Session (%s) state shutdown\n", bs->id); - blade_session_state_set(bs, BLADE_SESSION_STATE_CLEANUP); - - if (bs->connection) { - blade_connection_t *bc = blade_connectionmgr_connection_lookup(blade_handle_connectionmgr_get(bs->handle), bs->connection); - if (bc) { - blade_connection_disconnect(bc); - blade_connection_read_unlock(bc); - } - } - - // wait for the connection to disconnect before we resume session cleanup - while (bs->connection) ks_sleep(100); - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_session_onstate_run(blade_session_t *bs) -{ - cJSON *json = NULL; - - ks_assert(bs); - - while (blade_session_receiving_pop(bs, &json) == KS_STATUS_SUCCESS && json) { - blade_session_process(bs, json); - cJSON_Delete(json); - } - - blade_rpcmgr_request_timeouts(blade_handle_rpcmgr_get(blade_session_handle_get(bs))); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, ks_time_t ttl, blade_rpc_response_callback_t callback, void *data) -{ - blade_rpc_request_t *brpcreq = NULL; - const char *method = NULL; - const char *id = NULL; - - ks_assert(bs); - ks_assert(json); - - method = cJSON_GetObjectCstr(json, "method"); - - id = cJSON_GetObjectCstr(json, "id"); - ks_assert(id); - - if (method) { - ks_log(KS_LOG_DEBUG, "Session (%s) sending request (%s) for %s\n", bs->id, id, method); - - blade_rpc_request_create(&brpcreq, bs->handle, ks_pool_get(bs->handle), bs->id, json, callback, data); - ks_assert(brpcreq); - - // @todo update to get default ttl from configuration - if (ttl <= 0) ttl = 10; - blade_rpc_request_ttl_set(brpcreq, ttl); - - blade_rpcmgr_request_add(blade_handle_rpcmgr_get(bs->handle), brpcreq); - } else { - ks_log(KS_LOG_DEBUG, "Session (%s) sending response (%s)\n", bs->id, id); - } - - if (!bs->connection) { - blade_session_sending_push(bs, json); - } else { - blade_connection_t *bc = blade_connectionmgr_connection_lookup(blade_handle_connectionmgr_get(bs->handle), bs->connection); - if (!bc) { - blade_session_sending_push(bs, json); - return KS_STATUS_FAIL; - } - blade_connection_sending_push(bc, json); - blade_connection_read_unlock(bc); - } - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_session_process(blade_session_t *bs, cJSON *json) -{ - blade_handle_t *bh = NULL; - blade_rpc_request_t *brpcreq = NULL; - blade_rpc_response_t *brpcres = NULL; - const char *jsonrpc = NULL; - const char *id = NULL; - const char *method = NULL; - ks_bool_t disconnect = KS_FALSE; - - ks_assert(bs); - ks_assert(json); - - ks_log(KS_LOG_DEBUG, "Session (%s) processing\n", bs->id); - - bh = blade_session_handle_get(bs); - ks_assert(bh); - - jsonrpc = cJSON_GetObjectCstr(json, "jsonrpc"); - if (!jsonrpc || strcmp(jsonrpc, "2.0")) { - ks_log(KS_LOG_DEBUG, "Received message is not the expected protocol\n"); - // @todo send error response, code = -32600 (invalid request) - // @todo hangup session entirely? - return KS_STATUS_FAIL; - } - - - id = cJSON_GetObjectCstr(json, "id"); - if (!id) { - ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n"); - // @todo send error response, code = -32600 (invalid request) - // @todo hangup session entirely? - return KS_STATUS_FAIL; - } - - method = cJSON_GetObjectCstr(json, "method"); - if (method) { - // @note This is scenario 2 - // 2) Receiving a request (server: method callee or provider) - blade_rpc_t *brpc = NULL; - blade_rpc_request_callback_t callback = NULL; - cJSON *params = NULL; - const char *params_requester_nodeid = NULL; - const char *params_responder_nodeid = NULL; - - ks_log(KS_LOG_DEBUG, "Session (%s) receiving request (%s) for %s\n", bs->id, id, method); - - params = cJSON_GetObjectItem(json, "params"); - if (params) { - params_requester_nodeid = cJSON_GetObjectCstr(params, "requester-nodeid"); - params_responder_nodeid = cJSON_GetObjectCstr(params, "responder-nodeid"); - if (params_requester_nodeid && params_responder_nodeid && !blade_routemgr_local_check(blade_handle_routemgr_get(bh), params_responder_nodeid)) { - // not meant for local processing, continue with standard unicast routing for requests - blade_session_t *bs_router = blade_routemgr_route_lookup(blade_handle_routemgr_get(bh), params_responder_nodeid); - if (!bs_router) { - bs_router = blade_sessionmgr_upstream_lookup(blade_handle_sessionmgr_get(bh)); - if (!bs_router) { - cJSON *res = NULL; - cJSON *res_error = NULL; - - // @todo adjust error when this is master to be route unavailable - ks_log(KS_LOG_DEBUG, "Session (%s) request (%s => %s) but upstream session unavailable\n", blade_session_id_get(bs), params_requester_nodeid, params_responder_nodeid); - blade_rpc_error_raw_create(&res, &res_error, id, -32603, "Upstream session unavailable"); - - // needed in case this error must propagate further than the session which sent it - cJSON_AddStringToObject(res_error, "requester-nodeid", params_requester_nodeid); - cJSON_AddStringToObject(res_error, "responder-nodeid", params_responder_nodeid); // @todo responder-nodeid should become the local_nodeid to inform of which node actually responded - - blade_session_send(bs, res, 0, NULL, NULL); - return KS_STATUS_DISCONNECTED; - } - } - - if (bs_router == bs) { - // @todo avoid circular by sending back an error instead, really should not happen but check for posterity in case a node is misbehaving for some reason - } - - ks_log(KS_LOG_DEBUG, "Session (%s) request (%s => %s) routing (%s)\n", blade_session_id_get(bs), params_requester_nodeid, params_responder_nodeid, blade_session_id_get(bs_router)); - blade_session_send(bs_router, json, 0, NULL, NULL); - blade_session_read_unlock(bs_router); - - // @todo if this is a subscribe request to remove subscriptions, it must carry a field unsubscribed-channels for which - // subscriptions should be removed along the request path, regardless of whether it's the consumer requesting or the - // master due to a deauthorization, without respect to waiting for the response as it should be a gaurenteed operation - // even when requested by the subscriber. This unsubscribed-channels field is simply treated as a special field, regardless - // of the actual method of the request. - - return KS_STATUS_SUCCESS; - } - } - - // reach here if the request was not captured for routing, this SHOULD always mean the message is to be processed by local handlers - brpc = blade_rpcmgr_corerpc_lookup(blade_handle_rpcmgr_get(bs->handle), method); - - if (!brpc) { - cJSON *res = NULL; - cJSON *res_error = NULL; - - ks_log(KS_LOG_DEBUG, "Received unknown rpc method %s\n", method); - blade_rpc_error_raw_create(&res, &res_error, id, -32601, "RPC method not found"); - - // needed in case this error must propagate further than the session which sent it - if (params_requester_nodeid) cJSON_AddStringToObject(res_error, "requester-nodeid", params_requester_nodeid); - if (params_responder_nodeid) cJSON_AddStringToObject(res_error, "responder-nodeid", params_responder_nodeid); - - blade_session_send(bs, res, 0, NULL, NULL); - - return KS_STATUS_FAIL; - } - callback = blade_rpc_callback_get(brpc); - ks_assert(callback); - - blade_rpc_request_create(&brpcreq, bs->handle, ks_pool_get(bs->handle), bs->id, json, NULL, NULL); - ks_assert(brpcreq); - - disconnect = callback(brpcreq, blade_rpc_data_get(brpc)); - - blade_rpc_request_destroy(&brpcreq); - } else { - // @note This is scenario 4 - // 4) Receiving a response or error (client: method caller or consumer) - blade_rpc_response_callback_t callback = NULL; - cJSON *error = NULL; - cJSON *result = NULL; - cJSON *object = NULL; - - ks_log(KS_LOG_DEBUG, "Session (%s) receiving response (%s)\n", bs->id, id); - - error = cJSON_GetObjectItem(json, "error"); - result = cJSON_GetObjectItem(json, "result"); - object = error ? error : result; - - if (object) { - const char *object_requester_nodeid = cJSON_GetObjectCstr(object, "requester-nodeid"); - const char *object_responder_nodeid = cJSON_GetObjectCstr(object, "responder-nodeid"); - if (object_requester_nodeid && object_responder_nodeid && !blade_routemgr_local_check(blade_handle_routemgr_get(bh), object_requester_nodeid)) { - // not meant for local processing, continue with standard unicast routing for responses - blade_session_t *bs_router = blade_routemgr_route_lookup(blade_handle_routemgr_get(bh), object_requester_nodeid); - if (!bs_router) { - bs_router = blade_sessionmgr_upstream_lookup(blade_handle_sessionmgr_get(bh)); - if (!bs_router) { - ks_log(KS_LOG_DEBUG, "Session (%s) response (%s <= %s) but upstream session unavailable\n", blade_session_id_get(bs), object_requester_nodeid, object_responder_nodeid); - return KS_STATUS_DISCONNECTED; - } - } - - if (bs_router == bs) { - // @todo avoid circular, really should not happen but check for posterity in case a node is misbehaving for some reason - } - - ks_log(KS_LOG_DEBUG, "Session (%s) response (%s <= %s) routing (%s)\n", blade_session_id_get(bs), object_requester_nodeid, object_responder_nodeid, blade_session_id_get(bs_router)); - blade_session_send(bs_router, json, 0, NULL, NULL); - blade_session_read_unlock(bs_router); - - // @todo if this is a subscribe response to add a subscriber with the master as the responder-nodeid, it must have a - // subscribed-channels field which should be added for the requester-nodeid, this will ensure the subscriptions are - // added with respect to the master response and not immediately upon request. This subscribed-channels field is - // simply treated as a special field, regardless of the actual method of the request which is unavailable here. - - return KS_STATUS_SUCCESS; - } - } - - brpcreq = blade_rpcmgr_request_lookup(blade_handle_rpcmgr_get(bs->handle), id); - if (!brpcreq) { - // @todo hangup session entirely? - return KS_STATUS_FAIL; - } - blade_rpcmgr_request_remove(blade_handle_rpcmgr_get(bs->handle), brpcreq); - - callback = blade_rpc_request_callback_get(brpcreq); - - blade_rpc_response_create(&brpcres, bs->handle, ks_pool_get(bs), bs->id, brpcreq, json); - ks_assert(brpcres); - - if (callback) disconnect = callback(brpcres, blade_rpc_request_data_get(brpcreq)); - - blade_rpc_response_destroy(&brpcres); - } - - if (disconnect) { - // @todo hangup session entirely? - return KS_STATUS_FAIL; - } - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_sessionmgr.c b/libs/libblade/src/blade_sessionmgr.c deleted file mode 100644 index 359bf8b3e2..0000000000 --- a/libs/libblade/src/blade_sessionmgr.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_sessionmgr_s { - blade_handle_t *handle; - - blade_session_t *loopback; - blade_session_t *upstream; - ks_hash_t *sessions; // id, blade_session_t* - ks_hash_t *callbacks; // id, blade_session_callback_data_t* -}; - -struct blade_session_callback_data_s { - const char *id; - void *data; - blade_session_callback_t callback; -}; - - -static void blade_sessionmgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_sessionmgr_t *bsmgr = (blade_sessionmgr_t *)ptr; - - //ks_assert(bsmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -static void blade_session_callback_data_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_session_callback_data_t *bscd = (blade_session_callback_data_t *)ptr; - - ks_assert(bscd); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - ks_pool_free(&bscd->id); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_create(blade_sessionmgr_t **bsmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_sessionmgr_t *bsmgr = NULL; - - ks_assert(bsmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - bsmgr = ks_pool_alloc(pool, sizeof(blade_sessionmgr_t)); - bsmgr->handle = bh; - - ks_hash_create(&bsmgr->sessions, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bsmgr->sessions); - - ks_hash_create(&bsmgr->callbacks, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bsmgr->callbacks); - - ks_pool_set_cleanup(bsmgr, NULL, blade_sessionmgr_cleanup); - - *bsmgrP = bsmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_destroy(blade_sessionmgr_t **bsmgrP) -{ - blade_sessionmgr_t *bsmgr = NULL; - ks_pool_t *pool; - - ks_assert(bsmgrP); - ks_assert(*bsmgrP); - - bsmgr = *bsmgrP; - *bsmgrP = NULL; - - pool = ks_pool_get(bsmgr); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_sessionmgr_handle_get(blade_sessionmgr_t *bsmgr) -{ - ks_assert(bsmgr); - return bsmgr->handle; -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_startup(blade_sessionmgr_t *bsmgr, config_setting_t *config) -{ - ks_assert(bsmgr); - - blade_session_create(&bsmgr->loopback, bsmgr->handle, BLADE_SESSION_FLAGS_LOOPBACK, NULL); - ks_assert(bsmgr->loopback); - - ks_log(KS_LOG_DEBUG, "Session (%s) created\n", blade_session_id_get(bsmgr->loopback)); - - if (blade_session_startup(bsmgr->loopback) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", blade_session_id_get(bsmgr->loopback)); - blade_session_destroy(&bsmgr->loopback); - return KS_STATUS_FAIL; - } - - ks_log(KS_LOG_DEBUG, "Session (%s) started\n", blade_session_id_get(bsmgr->loopback)); - - blade_sessionmgr_session_add(bsmgr, bsmgr->loopback); - - blade_session_state_set(bsmgr->loopback, BLADE_SESSION_STATE_STARTUP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_shutdown(blade_sessionmgr_t *bsmgr) -{ - ks_hash_iterator_t *it = NULL; - - ks_assert(bsmgr); - - //if (bsmgr->loopback) { - // blade_session_hangup(bsmgr->loopback); - // ks_sleep_ms(100); - //} - - ks_hash_read_lock(bsmgr->sessions); - for (it = ks_hash_first(bsmgr->sessions, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - blade_session_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - blade_session_hangup(value); - } - ks_hash_read_unlock(bsmgr->sessions); - while (ks_hash_count(bsmgr->sessions) > 0) ks_sleep_ms(100); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_session_t *) blade_sessionmgr_loopback_lookup(blade_sessionmgr_t *bsmgr) -{ - ks_assert(bsmgr); - - blade_session_read_lock(bsmgr->loopback, KS_TRUE); - return bsmgr->loopback; -} - -KS_DECLARE(blade_session_t *) blade_sessionmgr_upstream_lookup(blade_sessionmgr_t *bsmgr) -{ - ks_assert(bsmgr); - - if (bsmgr->upstream) blade_session_read_lock(bsmgr->upstream, KS_TRUE); - return bsmgr->upstream; -} - -KS_DECLARE(blade_session_t *) blade_sessionmgr_session_lookup(blade_sessionmgr_t *bsmgr, const char *id) -{ - blade_session_t *bs = NULL; - - ks_assert(bsmgr); - ks_assert(id); - - bs = ks_hash_search(bsmgr->sessions, (void *)id, KS_READLOCKED); - if (bs) blade_session_read_lock(bs, KS_TRUE); - ks_hash_read_unlock(bsmgr->sessions); - - return bs; -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_session_add(blade_sessionmgr_t *bsmgr, blade_session_t *bs) -{ - char *key = NULL; - - ks_assert(bsmgr); - ks_assert(bs); - - key = ks_pstrdup(ks_pool_get(bsmgr), blade_session_id_get(bs)); - ks_hash_insert(bsmgr->sessions, (void *)key, bs); - - ks_log(KS_LOG_DEBUG, "Session Added: %s\n", key); - - if (blade_session_upstream(bs)) bsmgr->upstream = bs; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_session_remove(blade_sessionmgr_t *bsmgr, blade_session_t *bs) -{ - const char *id = NULL; - blade_routemgr_t *routemgr = NULL; - - ks_assert(bsmgr); - ks_assert(bs); - - blade_session_write_lock(bs, KS_TRUE); - - id = blade_session_id_get(bs); - ks_hash_remove(bsmgr->sessions, (void *)id); - - ks_log(KS_LOG_DEBUG, "Session Removed: %s\n", id); - - routemgr = blade_handle_routemgr_get(bsmgr->handle); - if (blade_session_upstream(bs)) { - bsmgr->upstream = NULL; - blade_routemgr_local_set(routemgr, NULL); - blade_routemgr_master_set(routemgr, NULL); - - ks_hash_read_lock(bsmgr->sessions); - for (ks_hash_iterator_t *it = ks_hash_first(bsmgr->sessions, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - blade_session_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - if (blade_session_loopback(value)) continue; - - blade_session_hangup(value); - } - ks_hash_read_unlock(bsmgr->sessions); - } - - blade_session_write_unlock(bs); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_callback_add(blade_sessionmgr_t *bsmgr, void *data, blade_session_callback_t callback, const char **id) -{ - ks_pool_t *pool = NULL; - blade_session_callback_data_t *bscd = NULL; - uuid_t uuid; - - ks_assert(bsmgr); - ks_assert(callback); - ks_assert(id); - - pool = ks_pool_get(bsmgr); - - ks_uuid(&uuid); - - bscd = ks_pool_alloc(pool, sizeof(blade_session_callback_data_t)); - bscd->id = ks_uuid_str(pool, &uuid); - bscd->data = data; - bscd->callback = callback; - - ks_pool_set_cleanup(bscd, NULL, blade_session_callback_data_cleanup); - - ks_hash_insert(bsmgr->callbacks, (void *)ks_pstrdup(pool, bscd->id), bscd); - - *id = bscd->id; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_sessionmgr_callback_remove(blade_sessionmgr_t *bsmgr, const char *id) -{ - ks_assert(bsmgr); - ks_assert(id); - - ks_hash_remove(bsmgr->callbacks, (void *)id); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(void) blade_sessionmgr_callback_execute(blade_sessionmgr_t *bsmgr, blade_session_t *bs, blade_session_state_condition_t condition) -{ - ks_assert(bsmgr); - ks_assert(bs); - - if (blade_session_state_get(bs) == BLADE_SESSION_STATE_NONE) return; - - ks_hash_read_lock(bsmgr->callbacks); - for (ks_hash_iterator_t *it = ks_hash_first(bsmgr->callbacks, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - blade_session_callback_data_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - value->callback(bs, condition, value->data); - } - ks_hash_read_unlock(bsmgr->callbacks); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_stack.c b/libs/libblade/src/blade_stack.c deleted file mode 100644 index 334e24a3af..0000000000 --- a/libs/libblade/src/blade_stack.c +++ /dev/null @@ -1,2139 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_handle_s { - ks_thread_pool_t *tpool; - - blade_transportmgr_t *transportmgr; - blade_rpcmgr_t *rpcmgr; - blade_routemgr_t *routemgr; - blade_subscriptionmgr_t *subscriptionmgr; - blade_mastermgr_t *mastermgr; - blade_connectionmgr_t *connectionmgr; - blade_sessionmgr_t *sessionmgr; - blade_restmgr_t *restmgr; -}; - -ks_bool_t blade_rpcroute_request_handler(blade_rpc_request_t *brpcreq, void *data); -ks_bool_t blade_rpcregister_request_handler(blade_rpc_request_t *brpcreq, void *data); -ks_bool_t blade_rpcregister_response_handler(blade_rpc_response_t *brpcres, void *data); -ks_bool_t blade_rpcpublish_request_handler(blade_rpc_request_t *brpcreq, void *data); -ks_bool_t blade_rpcauthorize_request_handler(blade_rpc_request_t *brpcreq, void *data); -ks_bool_t blade_rpclocate_request_handler(blade_rpc_request_t *brpcreq, void *data); -ks_bool_t blade_rpcexecute_request_handler(blade_rpc_request_t *brpcreq, void *data); -ks_bool_t blade_rpcsubscribe_request_handler(blade_rpc_request_t *brpcreq, void *data); -ks_bool_t blade_rpcsubscribe_response_handler(blade_rpc_response_t *brpcres, void *data); -ks_bool_t blade_rpcbroadcast_request_handler(blade_rpc_request_t *brpcreq, void *data); - - -static void blade_handle_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_handle_t *bh = (blade_handle_t *)ptr; - - ks_assert(bh); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - blade_transportmgr_destroy(&bh->transportmgr); - blade_rpcmgr_destroy(&bh->rpcmgr); - blade_routemgr_destroy(&bh->routemgr); - blade_subscriptionmgr_destroy(&bh->subscriptionmgr); - blade_mastermgr_destroy(&bh->mastermgr); - blade_connectionmgr_destroy(&bh->connectionmgr); - blade_sessionmgr_destroy(&bh->sessionmgr); - blade_restmgr_destroy(&bh->restmgr); - - ks_thread_pool_destroy(&bh->tpool); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP) -{ - blade_handle_t *bh = NULL; - ks_pool_t *pool = NULL; - ks_thread_pool_t *tpool = NULL; - - ks_assert(bhP); - - ks_pool_open(&pool); - ks_assert(pool); - - ks_thread_pool_create(&tpool, BLADE_HANDLE_TPOOL_MIN, BLADE_HANDLE_TPOOL_MAX, BLADE_HANDLE_TPOOL_STACK, KS_PRI_NORMAL, BLADE_HANDLE_TPOOL_IDLE); - ks_assert(tpool); - - bh = ks_pool_alloc(pool, sizeof(blade_handle_t)); - bh->tpool = tpool; - - blade_transportmgr_create(&bh->transportmgr, bh); - ks_assert(bh->transportmgr); - - blade_rpcmgr_create(&bh->rpcmgr, bh); - ks_assert(bh->rpcmgr); - - blade_routemgr_create(&bh->routemgr, bh); - ks_assert(bh->routemgr); - - blade_subscriptionmgr_create(&bh->subscriptionmgr, bh); - ks_assert(bh->subscriptionmgr); - - blade_mastermgr_create(&bh->mastermgr, bh); - ks_assert(bh->mastermgr); - - blade_connectionmgr_create(&bh->connectionmgr, bh); - ks_assert(bh->connectionmgr); - - blade_sessionmgr_create(&bh->sessionmgr, bh); - ks_assert(bh->sessionmgr); - - blade_restmgr_create(&bh->restmgr, bh); - ks_assert(bh->restmgr); - - ks_pool_set_cleanup(bh, NULL, blade_handle_cleanup); - - *bhP = bh; - - ks_log(KS_LOG_DEBUG, "Created\n"); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP) -{ - blade_handle_t *bh = NULL; - ks_pool_t *pool; - - ks_assert(bhP); - ks_assert(*bhP); - - bh = *bhP; - *bhP = NULL; - - // shutdown cannot happen inside of the cleanup callback because it'll lock a mutex for the pool during cleanup callbacks which connections and sessions need to finish their cleanup - // and more importantly, memory needs to remain intact until shutdown is completed to avoid various things hitting teardown before shutdown runs - blade_handle_shutdown(bh); - - pool = ks_pool_get(bh); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_handle_config(blade_handle_t *bh, config_setting_t *config) -{ - ks_assert(bh); - - if (!config) return KS_STATUS_FAIL; - if (!config_setting_is_group(config)) { - ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n"); - return KS_STATUS_FAIL; - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config) -{ - blade_rpc_t *brpc = NULL; - blade_transport_t *bt = NULL; - - ks_assert(bh); - - if (blade_handle_config(bh, config) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "blade_handle_config failed\n"); - return KS_STATUS_FAIL; - } - - // internal transport for secure websockets - blade_transport_wss_create(&bt, bh); - ks_assert(bt); - blade_transportmgr_default_set(bh->transportmgr, bt); - blade_transportmgr_transport_add(bh->transportmgr, bt); - - - // internal core rpcs for blade.xxx - blade_rpc_create(&brpc, bh, "blade.route", NULL, blade_rpcroute_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - blade_rpc_create(&brpc, bh, "blade.register", NULL, blade_rpcregister_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - blade_rpc_create(&brpc, bh, "blade.publish", NULL, blade_rpcpublish_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - blade_rpc_create(&brpc, bh, "blade.authorize", NULL, blade_rpcauthorize_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - blade_rpc_create(&brpc, bh, "blade.locate", NULL, blade_rpclocate_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - blade_rpc_create(&brpc, bh, "blade.execute", NULL, blade_rpcexecute_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - blade_rpc_create(&brpc, bh, "blade.subscribe", NULL, blade_rpcsubscribe_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - blade_rpc_create(&brpc, bh, "blade.broadcast", NULL, blade_rpcbroadcast_request_handler, NULL); - blade_rpcmgr_corerpc_add(bh->rpcmgr, brpc); - - - blade_transportmgr_startup(bh->transportmgr, config); - - blade_sessionmgr_startup(bh->sessionmgr, config); - - blade_mastermgr_startup(bh->mastermgr, config); - - blade_restmgr_startup(bh->restmgr, config); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh) -{ - ks_assert(bh); - - blade_mastermgr_shutdown(bh->mastermgr); - - blade_transportmgr_shutdown(bh->transportmgr); - - blade_connectionmgr_shutdown(bh->connectionmgr); - - blade_sessionmgr_shutdown(bh->sessionmgr); - - blade_restmgr_shutdown(bh->restmgr); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_thread_pool_t *) blade_handle_tpool_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->tpool; -} - -KS_DECLARE(blade_transportmgr_t *) blade_handle_transportmgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->transportmgr; -} - -KS_DECLARE(blade_rpcmgr_t *) blade_handle_rpcmgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->rpcmgr; -} - -KS_DECLARE(blade_routemgr_t *) blade_handle_routemgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->routemgr; -} - -KS_DECLARE(blade_subscriptionmgr_t *) blade_handle_subscriptionmgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->subscriptionmgr; -} - -KS_DECLARE(blade_mastermgr_t *) blade_handle_mastermgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->mastermgr; -} - -KS_DECLARE(blade_connectionmgr_t *) blade_handle_connectionmgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->connectionmgr; -} - -KS_DECLARE(blade_sessionmgr_t *) blade_handle_sessionmgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->sessionmgr; -} - -KS_DECLARE(blade_restmgr_t *) blade_handle_restmgr_get(blade_handle_t *bh) -{ - ks_assert(bh); - return bh->restmgr; -} - - -KS_DECLARE(ks_status_t) blade_handle_connect(blade_handle_t *bh, blade_connection_t **bcP, blade_identity_t *target, const char *session_id) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - blade_transport_t *bt = NULL; - blade_transport_callbacks_t *callbacks = NULL; - - ks_assert(bh); - ks_assert(target); - - // @todo mini state machine to deal with upstream establishment to avoid attempting multiple upstream connects at the same time? - if ((bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - blade_session_read_unlock(bs); - return KS_STATUS_DUPLICATE_OPERATION; - } - - bt = blade_transportmgr_transport_lookup(bh->transportmgr, blade_identity_parameter_lookup(target, "transport"), KS_TRUE); - ks_assert(bt); - - callbacks = blade_transport_callbacks_get(bt); - ks_assert(callbacks); - - if (callbacks->onconnect) ret = callbacks->onconnect(bcP, bt, target, session_id); - - return ret; -} - - -// BLADE PROTOCOL HANDLERS - -// @todo revisit all error sending. JSONRPC "error" should only be used for missing and invalid parameter errors, change the rest to internal errors for each of the corerpcs -// @todo all higher level errors should be handled by each of the calls internally so that a normal result response can be sent with an error block inside the result -// which is important for implementation of blade.execute where errors can be relayed back to the requester properly - -typedef struct blade_rpcregister_data_s blade_rpcregister_data_t; -struct blade_rpcregister_data_s { - blade_rpc_response_callback_t original_callback; - void *original_data; - const char *original_requestid; -}; - -typedef struct blade_rpcsubscribe_data_s blade_rpcsubscribe_data_t; -struct blade_rpcsubscribe_data_s { - blade_rpc_response_callback_t original_callback; - void *original_data; - const char *original_requestid; - blade_rpc_request_callback_t channel_callback; - void *channel_data; -}; - -ks_status_t blade_handle_rpcregister_raw(blade_handle_t *bh, const char *identity, const char *nodeid, blade_rpc_response_callback_t callback, blade_rpcregister_data_t *data); -ks_status_t blade_handle_rpcsubscribe_raw(blade_handle_t *bh, blade_rpcsubscribe_command_t command, const char *protocol, cJSON *channels, const char *subscriber, ks_bool_t downstream, blade_rpc_response_callback_t callback, blade_rpcsubscribe_data_t *data); - - -// blade.route request generator -KS_DECLARE(ks_status_t) blade_handle_rpcroute(blade_handle_t *bh, const char *nodeid, ks_bool_t remove, blade_rpc_response_callback_t callback, void *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - ks_pool_t *pool = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - - ks_assert(bh); - ks_assert(nodeid); - - - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - pool = ks_pool_get(bh); - ks_assert(pool); - - blade_rpc_request_raw_create(pool, &req, &req_params, NULL, "blade.route"); - - // fill in the req_params - cJSON_AddStringToObject(req_params, "nodeid", nodeid); - if (remove) cJSON_AddTrueToObject(req_params, "remove"); - - ks_log(KS_LOG_DEBUG, "Session (%s) route request (%s %s) started\n", blade_session_id_get(bs), remove ? "removing" : "adding", nodeid); - - ret = blade_session_send(bs, req, 0, callback, data); - -done: - if (req) cJSON_Delete(req); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -// blade.route request handler -ks_bool_t blade_rpcroute_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_params_nodeid = NULL; - cJSON *req_params_remove = NULL; - ks_bool_t remove = KS_FALSE; - cJSON *res = NULL; - cJSON *res_result = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(bh->sessionmgr, blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) route request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_nodeid = cJSON_GetObjectCstr(req_params, "nodeid"); - if (!req_params_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) route request missing 'nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - req_params_remove = cJSON_GetObjectItem(req_params, "remove"); - remove = req_params_remove && req_params_remove->type == cJSON_True; - - ks_log(KS_LOG_DEBUG, "Session (%s) route request (%s %s) processing\n", blade_session_id_get(bs), remove ? "removing" : "adding", req_params_nodeid); - - if (remove) { - blade_session_route_remove(bs, req_params_nodeid); - blade_routemgr_route_remove(blade_handle_routemgr_get(bh), req_params_nodeid); - } else { - blade_session_route_add(bs, req_params_nodeid); - blade_routemgr_route_add(blade_handle_routemgr_get(bh), req_params_nodeid, blade_session_id_get(bs)); - } - - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - blade_session_send(bs, res, 0, NULL, NULL); - -done: - - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return KS_FALSE; -} - - -static void blade_rpcregister_data_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_rpcregister_data_t *brpcrd = (blade_rpcregister_data_t *)ptr; - - ks_assert(brpcrd); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (brpcrd->original_requestid) ks_pool_free(&brpcrd->original_requestid); - break; - case KS_MPCL_DESTROY: - break; - } -} - -// blade.register request generator -KS_DECLARE(ks_status_t) blade_handle_rpcregister(blade_handle_t *bh, const char *identity, blade_rpc_response_callback_t callback, void *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - const char *localid = NULL; - blade_rpcregister_data_t *temp_data = NULL; - - ks_assert(bh); - ks_assert(identity); - - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - temp_data = (blade_rpcregister_data_t *)ks_pool_alloc(ks_pool_get(bh), sizeof(blade_rpcregister_data_t)); - temp_data->original_callback = callback; - temp_data->original_data = data; - ks_pool_set_cleanup(temp_data, NULL, blade_rpcregister_data_cleanup); - - blade_routemgr_local_copy(bh->routemgr, &localid); - - ret = blade_handle_rpcregister_raw(bh, identity, localid, blade_rpcregister_response_handler, temp_data); - - ks_pool_free(&localid); - - ks_log(KS_LOG_DEBUG, "Session (%s) register request (%s) started\n", blade_session_id_get(bs), identity); - -done: - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -ks_status_t blade_handle_rpcregister_raw(blade_handle_t *bh, const char *identity, const char *nodeid, blade_rpc_response_callback_t callback, blade_rpcregister_data_t *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - ks_pool_t *pool = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - - ks_assert(bh); - ks_assert(identity); - - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - pool = ks_pool_get(bh); - ks_assert(pool); - - blade_rpc_request_raw_create(pool, &req, &req_params, NULL, "blade.register"); - - // fill in the req_params - cJSON_AddStringToObject(req_params, "identity", identity); - cJSON_AddStringToObject(req_params, "nodeid", nodeid); - - ret = blade_session_send(bs, req, 0, callback, data); - -done: - if (req) cJSON_Delete(req); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -// blade.register request handler -ks_bool_t blade_rpcregister_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - ks_pool_t *pool = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_params_identity = NULL; - const char *req_params_nodeid = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - blade_identity_t *identity = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - pool = ks_pool_get(bh); - ks_assert(pool); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) register request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_identity = cJSON_GetObjectCstr(req_params, "identity"); - if (!req_params_identity) { - ks_log(KS_LOG_DEBUG, "Session (%s) register request missing 'identity'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params identity"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - blade_identity_create(&identity, pool); - if (blade_identity_parse(identity, req_params_identity) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Session (%s) register request invalid 'identity'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params identity"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_nodeid = cJSON_GetObjectCstr(req_params, "nodeid"); - if (!req_params_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) register request missing 'nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - ks_log(KS_LOG_DEBUG, "Session (%s) register request (%s for %s) processing\n", blade_session_id_get(bs), req_params_identity, req_params_nodeid); - - if (blade_routemgr_master_local(blade_handle_routemgr_get(bh))) { - // @todo add identity mapping to nodeid, normally handled in the response handler - blade_routemgr_identity_add(bh->routemgr, identity, req_params_nodeid); - - // @todo this is the masters chance to do any additional validation on the identity registration, just trust it for now - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - - cJSON_AddStringToObject(res_result, "identity", req_params_identity); - cJSON_AddStringToObject(res_result, "nodeid", req_params_nodeid); - - // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, 0, NULL, NULL); - } else { - blade_rpcregister_data_t *temp_data = (blade_rpcregister_data_t *)ks_pool_alloc(pool, sizeof(blade_rpcregister_data_t)); - temp_data->original_requestid = ks_pstrdup(pool, blade_rpc_request_messageid_get(brpcreq)); - ks_pool_set_cleanup(temp_data, NULL, blade_rpcregister_data_cleanup); - - blade_handle_rpcregister_raw(bh, req_params_identity, req_params_nodeid, blade_rpcregister_response_handler, temp_data); - } - -done: - if (identity) blade_identity_destroy(&identity); - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return KS_FALSE; -} - -// blade.register response handler -ks_bool_t blade_rpcregister_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - ks_bool_t ret = KS_FALSE; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - blade_rpcregister_data_t *temp_data = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - const char *res_result_identity = NULL; - const char *res_result_nodeid = NULL; - blade_identity_t *identity = NULL; - - ks_assert(brpcres); - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(bh->sessionmgr, blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - temp_data = (blade_rpcregister_data_t *)data; - - res = blade_rpc_response_message_get(brpcres); - ks_assert(res); - - res_result = cJSON_GetObjectItem(res, "result"); - if (!res_result) { - ks_log(KS_LOG_DEBUG, "Session (%s) register response missing 'result' object\n", blade_session_id_get(bs)); - goto done; - } - - res_result_identity = cJSON_GetObjectCstr(res_result, "identity"); - if (!res_result_identity) { - ks_log(KS_LOG_DEBUG, "Session (%s) register response missing 'identity'\n", blade_session_id_get(bs)); - goto done; - } - - blade_identity_create(&identity, ks_pool_get(bh)); - - if (blade_identity_parse(identity, res_result_identity) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Session (%s) register response invalid 'identity'\n", blade_session_id_get(bs)); - goto done; - } - - res_result_nodeid = cJSON_GetObjectCstr(res_result, "nodeid"); - if (!res_result_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) register response missing 'nodeid'\n", blade_session_id_get(bs)); - goto done; - } - - blade_routemgr_identity_add(bh->routemgr, identity, res_result_nodeid); - - // @note this should only happen on the last response, received by the registering node - if (temp_data && temp_data->original_callback) ret = temp_data->original_callback(brpcres, temp_data->original_data); - - if (temp_data && temp_data->original_requestid) { - blade_session_t *relay = NULL; - if (!(relay = blade_routemgr_route_lookup(bh->routemgr, res_result_nodeid))) { - goto done; - } - - blade_rpc_response_raw_create(&res, &res_result, temp_data->original_requestid); - - cJSON_AddStringToObject(res_result, "identity", res_result_identity); - cJSON_AddStringToObject(res_result, "nodeid", res_result_nodeid); - - blade_session_send(relay, res, 0, NULL, NULL); - - cJSON_Delete(res); - - blade_session_read_unlock(relay); - } - -done: - if (temp_data) ks_pool_free(&temp_data); - if (identity) blade_identity_destroy(&identity); - blade_session_read_unlock(bs); - return ret; -} - -// blade.publish request generator -KS_DECLARE(ks_status_t) blade_handle_rpcpublish(blade_handle_t *bh, blade_rpcpublish_command_t command, const char *protocol, cJSON *channels, blade_rpc_response_callback_t callback, void *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - - ks_assert(bh); - ks_assert(protocol); - - // @todo consideration for the Master trying to publish a protocol, with no upstream - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - // @todo validate command and parameters - switch (command) { - case BLADE_RPCPUBLISH_COMMAND_CONTROLLER_ADD: - break; - case BLADE_RPCPUBLISH_COMMAND_CONTROLLER_REMOVE: - break; - case BLADE_RPCPUBLISH_COMMAND_CHANNEL_ADD: - if (!channels || cJSON_GetArraySize(channels) <= 0) { - ret = KS_STATUS_ARG_NULL; - goto done; - } - break; - case BLADE_RPCPUBLISH_COMMAND_CHANNEL_REMOVE: - break; - default: - ret = KS_STATUS_ARG_INVALID; - goto done; - } - - // create the response - blade_rpc_request_raw_create(ks_pool_get(bh), &req, &req_params, NULL, "blade.publish"); - - cJSON_AddNumberToObject(req_params, "command", command); - cJSON_AddStringToObject(req_params, "protocol", protocol); - - blade_routemgr_local_pack(bh->routemgr, req_params, "requester-nodeid"); - - if (!blade_routemgr_master_pack(bh->routemgr, req_params, "responder-nodeid")) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - if (channels) cJSON_AddItemToObject(req_params, "channels", cJSON_Duplicate(channels, 1)); - - // @todo add a parameter containing a block of json for schema definitions for each of the methods being published - - ks_log(KS_LOG_DEBUG, "Session (%s) publish request started\n", blade_session_id_get(bs)); - - ret = blade_session_send(bs, req, 0, callback, data); - -done: - if (req) cJSON_Delete(req); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -// blade.publish request handler -ks_bool_t blade_rpcpublish_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - cJSON *req_params_channels = NULL; - cJSON *req_params_channels_element = NULL; - cJSON *req_params_channels_element_flags = NULL; - cJSON *req_params_command = NULL; - blade_rpcpublish_command_t command = BLADE_RPCPUBLISH_COMMAND_NONE; - const char *req_params_protocol = NULL; - const char *req_params_requester_nodeid = NULL; - const char *req_params_responder_nodeid = NULL; - const char *req_params_channels_element_name = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - // @todo error messages in here SHOULD include requester-nodeid and responder-nodeid in the error responses to ensure - // proper return routing of the error message - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_command = cJSON_GetObjectItem(req_params, "command"); - if (!req_params_command) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'command'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params command"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - command = (blade_rpcpublish_command_t)req_params_command->valueint; - switch (command) { - case BLADE_RPCPUBLISH_COMMAND_CONTROLLER_ADD: - case BLADE_RPCPUBLISH_COMMAND_CONTROLLER_REMOVE: - case BLADE_RPCPUBLISH_COMMAND_CHANNEL_ADD: - case BLADE_RPCPUBLISH_COMMAND_CHANNEL_REMOVE: break; - default: goto done; - } - - req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - if (!req_params_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'protocol'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); - if (!req_params_requester_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'requester-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params requester-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); - if (!req_params_responder_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'responder-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params responder-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - if (!blade_routemgr_master_check(bh->routemgr, req_params_responder_nodeid)) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request invalid 'responder-nodeid' (%s)\n", blade_session_id_get(bs), req_params_responder_nodeid); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params responder-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - // @todo get enumeration parameter to represent a publish command, including add_protocol, remove_protocol, and update_channels - // @todo switch channels to separate add_channels and remove_channels - - req_params_channels = cJSON_GetObjectItem(req_params, "channels"); - if (req_params_channels) { - if (req_params_channels->type != cJSON_Array) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request invalid 'channels' type, expected array\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params channels"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - cJSON_ArrayForEach(req_params_channels_element, req_params_channels) { - if (req_params_channels_element->type != cJSON_Object) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request invalid 'channels' element type, expected object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params channels"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_channels_element_name = cJSON_GetObjectCstr(req_params_channels_element, "name"); - if (!req_params_channels_element_name) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request missing 'channels' element name\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params channels element name"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_channels_element_flags = cJSON_GetObjectItem(req_params_channels_element, "flags"); - if (req_params_channels_element_flags && req_params_channels_element_flags->type != cJSON_Number) { - ks_log(KS_LOG_DEBUG, "Session (%s) publish request invalid 'channels' element flags type, expected number\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params channels element flags type"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - } - } - - ks_log(KS_LOG_DEBUG, "Session (%s) publish request (%s to %s) processing\n", blade_session_id_get(bs), req_params_requester_nodeid, req_params_responder_nodeid); - - // @todo switch on publish command, make the following code for add_protocol - switch (command) { - case BLADE_RPCPUBLISH_COMMAND_CONTROLLER_ADD: - blade_mastermgr_protocol_controller_add(bh->mastermgr, req_params_protocol, req_params_requester_nodeid); - if (req_params_channels) { - cJSON_ArrayForEach(req_params_channels_element, req_params_channels) { - req_params_channels_element_name = cJSON_GetObjectCstr(req_params_channels_element, "name"); - req_params_channels_element_flags = cJSON_GetObjectItem(req_params_channels_element, "flags"); - - blade_mastermgr_protocol_channel_add(bh->mastermgr, req_params_protocol, req_params_channels_element_name, (blade_channel_flags_t)req_params_channels_element_flags->valueint); - } - } - break; - case BLADE_RPCPUBLISH_COMMAND_CONTROLLER_REMOVE: - blade_mastermgr_protocol_controller_remove(bh->mastermgr, req_params_protocol, req_params_requester_nodeid); - break; - case BLADE_RPCPUBLISH_COMMAND_CHANNEL_ADD: - if (req_params_channels) { - cJSON_ArrayForEach(req_params_channels_element, req_params_channels) { - req_params_channels_element_name = cJSON_GetObjectCstr(req_params_channels_element, "name"); - req_params_channels_element_flags = cJSON_GetObjectItem(req_params_channels_element, "flags"); - blade_mastermgr_protocol_channel_add(bh->mastermgr, req_params_protocol, req_params_channels_element_name, (blade_channel_flags_t)req_params_channels_element_flags->valueint); - } - } - break; - case BLADE_RPCPUBLISH_COMMAND_CHANNEL_REMOVE: - if (req_params_channels) { - cJSON_ArrayForEach(req_params_channels_element, req_params_channels) { - req_params_channels_element_name = cJSON_GetObjectCstr(req_params_channels_element, "name"); - blade_mastermgr_protocol_channel_remove(bh->mastermgr, req_params_protocol, req_params_channels_element_name); - } - } - break; - default: - goto done; - } - - - // build the actual response finally - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - - cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); - cJSON_AddStringToObject(res_result, "requester-nodeid", req_params_requester_nodeid); - cJSON_AddStringToObject(res_result, "responder-nodeid", req_params_responder_nodeid); - // @todo include a list of channels that failed to be added or removed if applicable? - - // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, 0, NULL, NULL); - -done: - - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return KS_FALSE; -} - - -// blade.authorize request generator -KS_DECLARE(ks_status_t) blade_handle_rpcauthorize(blade_handle_t *bh, const char *nodeid, ks_bool_t remove, const char *protocol, cJSON *channels, blade_rpc_response_callback_t callback, void *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - - ks_assert(bh); - ks_assert(nodeid); - ks_assert(protocol); - ks_assert(channels); - - // @todo consideration for the Master trying to publish a protocol, with no upstream - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - blade_rpc_request_raw_create(ks_pool_get(bh), &req, &req_params, NULL, "blade.authorize"); - - // fill in the req_params - cJSON_AddStringToObject(req_params, "protocol", protocol); - if (remove) cJSON_AddTrueToObject(req_params, "remove"); - cJSON_AddStringToObject(req_params, "authorized-nodeid", nodeid); - - blade_routemgr_local_pack(bh->routemgr, req_params, "requester-nodeid"); - - if (!blade_routemgr_master_pack(bh->routemgr, req_params, "responder-nodeid")) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - cJSON_AddItemToObject(req_params, "channels", cJSON_Duplicate(channels, 1)); - - // @todo add a parameter containing a block of json for schema definitions for each of the methods being published - - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request started\n", blade_session_id_get(bs)); - - ret = blade_session_send(bs, req, 0, callback, data); - -done: - if (req) cJSON_Delete(req); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -// blade.authorize request handler -ks_bool_t blade_rpcauthorize_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - cJSON *req_params_channels = NULL; - cJSON *req_params_remove = NULL; - cJSON *channel = NULL; - ks_bool_t remove = KS_FALSE; - const char *req_params_protocol = NULL; - const char *req_params_authorized_nodeid = NULL; - const char *req_params_requester_nodeid = NULL; - const char *req_params_responder_nodeid = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - cJSON *res_result_authorized_channels = NULL; - cJSON *res_result_unauthorized_channels = NULL; - cJSON *res_result_failed_channels = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - // @todo error messages in here need to include requester-nodeid and responder-nodeid in the error responses to ensure - // proper return routing of the error message - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - if (!req_params_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request missing 'protocol'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_remove = cJSON_GetObjectItem(req_params, "remove"); - if (req_params_remove && req_params_remove->type == cJSON_True) remove = KS_TRUE; - - req_params_authorized_nodeid = cJSON_GetObjectCstr(req_params, "authorized-nodeid"); - if (!req_params_authorized_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request missing 'authorized-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params authorized-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); - if (!req_params_requester_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request missing 'requester-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params requester-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); - if (!req_params_responder_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request missing 'responder-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params responder-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_channels = cJSON_GetObjectItem(req_params, "channels"); - if (!req_params_channels) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request missing 'channels'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params channels"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - if (req_params_channels->type != cJSON_Array) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request invalid 'channels' type, expected array\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params channels"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - cJSON_ArrayForEach(channel, req_params_channels) { - if (channel->type != cJSON_String) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request invalid 'channels' element type, expected string\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params channels"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - } - - if (!blade_routemgr_master_check(bh->routemgr, req_params_responder_nodeid)) { - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request invalid 'responder-nodeid' (%s)\n", blade_session_id_get(bs), req_params_responder_nodeid); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params responder-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - ks_log(KS_LOG_DEBUG, "Session (%s) authorize request (%s to %s) processing\n", blade_session_id_get(bs), req_params_requester_nodeid, req_params_responder_nodeid); - - // build the actual response finally - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - - cJSON_ArrayForEach(channel, req_params_channels) { - if (blade_mastermgr_protocol_channel_authorize(bh->mastermgr, remove, req_params_protocol, channel->valuestring, req_params_requester_nodeid, req_params_authorized_nodeid) == KS_STATUS_SUCCESS) { - if (remove) { - if (!res_result_unauthorized_channels) res_result_unauthorized_channels = cJSON_CreateArray(); - cJSON_AddItemToArray(res_result_unauthorized_channels, cJSON_CreateString(channel->valuestring)); - } else { - if (!res_result_authorized_channels) res_result_authorized_channels = cJSON_CreateArray(); - cJSON_AddItemToArray(res_result_authorized_channels, cJSON_CreateString(channel->valuestring)); - } - } else { - if (!res_result_failed_channels) res_result_failed_channels = cJSON_CreateArray(); - cJSON_AddItemToArray(res_result_failed_channels, cJSON_CreateString(channel->valuestring)); - } - } - - cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); - cJSON_AddStringToObject(res_result, "authorized-nodeid", req_params_authorized_nodeid); - cJSON_AddStringToObject(res_result, "requester-nodeid", req_params_requester_nodeid); - cJSON_AddStringToObject(res_result, "responder-nodeid", req_params_responder_nodeid); - if (res_result_authorized_channels) cJSON_AddItemToObject(res_result, "authorized-channels", res_result_authorized_channels); - if (res_result_unauthorized_channels) cJSON_AddItemToObject(res_result, "unauthorized-channels", res_result_unauthorized_channels); - if (res_result_failed_channels) cJSON_AddItemToObject(res_result, "failed-channels", res_result_failed_channels); - - // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, 0, NULL, NULL); - - if (res_result_unauthorized_channels) { - blade_handle_rpcsubscribe_raw(bh, BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_REMOVE, req_params_protocol, res_result_unauthorized_channels, req_params_authorized_nodeid, KS_TRUE, NULL, NULL); - } - -done: - - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return KS_FALSE; -} - - -// blade.locate request generator -// @todo discuss system to support caching locate results, and internally subscribing to receive event updates related to protocols which have been located -// to ensure local caches remain synced when protocol controllers change, but this requires additional filters for event propagating to avoid broadcasting -// every protocol update to everyone which may actually be a better way than an explicit locate request -KS_DECLARE(ks_status_t) blade_handle_rpclocate(blade_handle_t *bh, const char *protocol, blade_rpc_response_callback_t callback, void *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - - ks_assert(bh); - ks_assert(protocol); - - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - blade_rpc_request_raw_create(ks_pool_get(bh), &req, &req_params, NULL, "blade.locate"); - - // fill in the req_params - cJSON_AddStringToObject(req_params, "protocol", protocol); - - blade_routemgr_local_pack(bh->routemgr, req_params, "requester-nodeid"); - - if (!blade_routemgr_master_pack(bh->routemgr, req_params, "responder-nodeid")) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - ks_log(KS_LOG_DEBUG, "Session (%s) locate request started\n", blade_session_id_get(bs)); - - ret = blade_session_send(bs, req, 0, callback, data); - -done: - if (req) cJSON_Delete(req); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -// blade.locate request handler -ks_bool_t blade_rpclocate_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_params_protocol = NULL; - const char *req_params_requester_nodeid = NULL; - const char *req_params_responder_nodeid = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - cJSON *res_result_controllers = NULL; - blade_protocol_t *bp = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - // @todo error messages in here need to include requester-nodeid and responder-nodeid in the error responses to ensure - // proper return routing of the error message - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - if (!req_params_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'protocol'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); - if (!req_params_requester_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'requester-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params requester-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); - if (!req_params_responder_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate request missing 'responder-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params responder-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - if (!blade_routemgr_master_check(bh->routemgr, req_params_responder_nodeid)) { - ks_log(KS_LOG_DEBUG, "Session (%s) locate request invalid 'responder-nodeid' (%s)\n", blade_session_id_get(bs), req_params_responder_nodeid); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Invalid params responder-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - ks_log(KS_LOG_DEBUG, "Session (%s) locate request (%s to %s) processing\n", blade_session_id_get(bs), req_params_requester_nodeid, req_params_responder_nodeid); - - bp = blade_mastermgr_protocol_lookup(bh->mastermgr, req_params_protocol, KS_FALSE); - if (bp) { - res_result_controllers = blade_protocol_controller_pack(bp); - blade_protocol_read_unlock(bp); - } - - - // build the actual response finally - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - - cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); - cJSON_AddStringToObject(res_result, "requester-nodeid", req_params_requester_nodeid); - cJSON_AddStringToObject(res_result, "responder-nodeid", req_params_responder_nodeid); - if (res_result_controllers) cJSON_AddItemToObject(res_result, "controllers", res_result_controllers); - - // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, 0, NULL, NULL); - -done: - - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return KS_FALSE; -} - - -// blade.execute request generator -KS_DECLARE(ks_status_t) blade_handle_rpcexecute(blade_handle_t *bh, const char *nodeid, const char *method, const char *protocol, cJSON *params, ks_time_t ttl, blade_rpc_response_callback_t callback, void *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - - ks_assert(bh); - ks_assert(nodeid); - ks_assert(method); - ks_assert(protocol); - - if (!(bs = blade_routemgr_route_lookup(blade_handle_routemgr_get(bh), nodeid))) { - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - } - - blade_rpc_request_raw_create(ks_pool_get(bh), &req, &req_params, NULL, "blade.execute"); - - cJSON_AddStringToObject(req_params, "method", method); - cJSON_AddStringToObject(req_params, "protocol", protocol); - - blade_routemgr_local_pack(bh->routemgr, req_params, "requester-nodeid"); - - cJSON_AddStringToObject(req_params, "responder-nodeid", nodeid); - - if (params) cJSON_AddItemToObject(req_params, "params", cJSON_Duplicate(params, 1)); - - ks_log(KS_LOG_DEBUG, "Session (%s) execute request started\n", blade_session_id_get(bs)); - - ret = blade_session_send(bs, req, 0, callback, data); - -done: - if (req) cJSON_Delete(req); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -// blade.execute request handler -ks_bool_t blade_rpcexecute_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - ks_bool_t ret = KS_FALSE; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_params_method = NULL; - const char *req_params_protocol = NULL; - const char *req_params_requester_nodeid = NULL; - const char *req_params_responder_nodeid = NULL; - blade_rpc_t *brpc = NULL; - blade_rpc_request_callback_t callback = NULL; - cJSON *res = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - // @todo error messages in here need to include requester-nodeid and responder-nodeid in the error responses to ensure - // proper return routing of the error message - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_method = cJSON_GetObjectCstr(req_params, "method"); - if (!req_params_method) { - ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'method'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params method"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - if (!req_params_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'protocol'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); - if (!req_params_requester_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'requester-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params requester-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); - if (!req_params_responder_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) execute request missing 'responder-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params responder-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - ks_log(KS_LOG_DEBUG, "Session (%s) execute request (%s to %s) processing\n", blade_session_id_get(bs), req_params_requester_nodeid, req_params_responder_nodeid); - - // @todo pull out nested params block if it exists and check against schema later, so blade_rpc_t should be able to carry a schema with it, even though blade.xxx may not associate one - - brpc = blade_rpcmgr_protocolrpc_lookup(blade_handle_rpcmgr_get(bh), req_params_method, req_params_protocol); - if (!brpc) { - ks_log(KS_LOG_DEBUG, "Session (%s) execute request unknown method\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Unknown params method"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - callback = blade_rpc_callback_get(brpc); - if (callback) ret = callback(brpcreq, blade_rpc_data_get(brpc)); - -done: - - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -KS_DECLARE(const char *) blade_rpcexecute_request_requester_nodeid_get(blade_rpc_request_t *brpcreq) -{ - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_requester_nodeid = NULL; - - ks_assert(brpcreq); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (req_params) req_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); - - return req_requester_nodeid; -} - -KS_DECLARE(const char *) blade_rpcexecute_request_responder_nodeid_get(blade_rpc_request_t *brpcreq) -{ - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_responder_nodeid = NULL; - - ks_assert(brpcreq); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (req_params) req_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); - - return req_responder_nodeid; -} - -KS_DECLARE(cJSON *) blade_rpcexecute_request_params_get(blade_rpc_request_t *brpcreq) -{ - cJSON *req = NULL; - cJSON *req_params = NULL; - cJSON *req_params_params = NULL; - - ks_assert(brpcreq); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (req_params) req_params_params = cJSON_GetObjectItem(req_params, "params"); - - return req_params_params; -} - -KS_DECLARE(cJSON *) blade_rpcexecute_response_result_get(blade_rpc_response_t *brpcres) -{ - cJSON *res = NULL; - cJSON *res_result = NULL; - cJSON *res_result_result = NULL; - - ks_assert(brpcres); - - res = blade_rpc_response_message_get(brpcres); - ks_assert(res); - - res_result = cJSON_GetObjectItem(res, "result"); - if (res_result) res_result_result = cJSON_GetObjectItem(res_result, "result"); - - return res_result_result; -} - -// @note added blade_rpc_request_duplicate() to support async responding where the callbacks return immediately and the blade_rpc_request_t will be destroyed, -// in such cases duplicate the request to retain a copy for passing to blade_protocol_execute_response_send when sending the response as it contains everything -// needed to produce a response except the inner result block for blade.execute and call blade_rpc_request_destroy() to clean up the duplicate when finished -KS_DECLARE(void) blade_rpcexecute_response_send(blade_rpc_request_t *brpcreq, cJSON *result) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - //const char *req_params_method = NULL; - const char *req_params_protocol = NULL; - const char *req_params_requester_nodeid = NULL; - const char *req_params_responder_nodeid = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - ks_assert(req_params); - - req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - ks_assert(req_params_protocol); - - req_params_requester_nodeid = cJSON_GetObjectCstr(req_params, "requester-nodeid"); - ks_assert(req_params_requester_nodeid); - - req_params_responder_nodeid = cJSON_GetObjectCstr(req_params, "responder-nodeid"); - ks_assert(req_params_responder_nodeid); - - // build the actual response finally, wrap this into blade_protocol_execute_response_send() - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - - cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); - cJSON_AddStringToObject(res_result, "requester-nodeid", req_params_requester_nodeid); - cJSON_AddStringToObject(res_result, "responder-nodeid", req_params_responder_nodeid); - if (result) cJSON_AddItemToObject(res_result, "result", cJSON_Duplicate(result, 1)); - - // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, 0, NULL, NULL); - - cJSON_Delete(res); - - blade_session_read_unlock(bs); -} - - -static void blade_rpcsubscribe_data_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_rpcsubscribe_data_t *brpcsd = (blade_rpcsubscribe_data_t *)ptr; - - ks_assert(brpcsd); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (brpcsd->original_requestid) ks_pool_free(&brpcsd->original_requestid); - break; - case KS_MPCL_DESTROY: - break; - } -} - -// blade.subscribe request generator -KS_DECLARE(ks_status_t) blade_handle_rpcsubscribe(blade_handle_t *bh, - blade_rpcsubscribe_command_t command, - const char *protocol, - cJSON *channels, - blade_rpc_response_callback_t callback, - void *data, - blade_rpc_request_callback_t channel_callback, - void *channel_data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - const char *localid = NULL; - blade_rpcsubscribe_data_t *temp_data = NULL; - - ks_assert(bh); - ks_assert(protocol); - ks_assert(channels); - - // @note this is always produced by a subscriber, and sent upstream, master will only use the internal raw call - if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - blade_routemgr_local_copy(bh->routemgr, &localid); - ks_assert(localid); - - // @note since this is allocated in the handle's pool, if the handle is shutdown during a pending request, then the data - // memory will be cleaned up with the handle, otherwise should be cleaned up in the response callback - temp_data = (blade_rpcsubscribe_data_t *)ks_pool_alloc(ks_pool_get(bh), sizeof(blade_rpcsubscribe_data_t)); - temp_data->original_callback = callback; - temp_data->original_data = data; - temp_data->channel_callback = channel_callback; - temp_data->channel_data = channel_data; - ks_pool_set_cleanup(temp_data, NULL, blade_rpcsubscribe_data_cleanup); - - ret = blade_handle_rpcsubscribe_raw(bh, command, protocol, channels, localid, KS_FALSE, blade_rpcsubscribe_response_handler, temp_data); - - ks_pool_free(&localid); - -done: - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -ks_status_t blade_handle_rpcsubscribe_raw(blade_handle_t *bh, - blade_rpcsubscribe_command_t command, - const char *protocol, - cJSON *channels, - const char *subscriber, - ks_bool_t downstream, - blade_rpc_response_callback_t callback, - blade_rpcsubscribe_data_t *data) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_session_t *bs = NULL; - ks_pool_t *pool = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - - ks_assert(bh); - ks_assert(protocol); - ks_assert(channels); - ks_assert(subscriber); - - if (downstream) { - // @note if a master is sending a downstream update, it may only remove subscriptions, it cannot force a subscription without the subscriber providing the callback - if (command != BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_REMOVE) { - ret = KS_STATUS_NOT_ALLOWED; - goto done; - } - if (!(bs = blade_routemgr_route_lookup(blade_handle_routemgr_get(bh), subscriber))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - } - else if (!(bs = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - ret = KS_STATUS_DISCONNECTED; - goto done; - } - - pool = ks_pool_get(bh); - ks_assert(pool); - - if (command == BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_REMOVE) { - cJSON *channel = NULL; - cJSON_ArrayForEach(channel, channels) { - blade_subscriptionmgr_subscriber_remove(bh->subscriptionmgr, NULL, protocol, channel->valuestring, subscriber); - } - } - - blade_rpc_request_raw_create(pool, &req, &req_params, NULL, "blade.subscribe"); - - cJSON_AddNumberToObject(req_params, "command", command); - cJSON_AddStringToObject(req_params, "protocol", protocol); - cJSON_AddStringToObject(req_params, "subscriber-nodeid", subscriber); - if (downstream) cJSON_AddTrueToObject(req_params, "downstream"); - cJSON_AddItemToObject(req_params, "channels", cJSON_Duplicate(channels, 1)); - - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe request started\n", blade_session_id_get(bs)); - - ret = blade_session_send(bs, req, 0, blade_rpcsubscribe_response_handler, data); - -done: - if (req) cJSON_Delete(req); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - -// blade.subscribe request handler -ks_bool_t blade_rpcsubscribe_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - ks_pool_t *pool = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - cJSON *req_params_command = NULL; - blade_rpcsubscribe_command_t command = BLADE_RPCSUBSCRIBE_COMMAND_NONE; - const char *req_params_protocol = NULL; - const char *req_params_subscriber_nodeid = NULL; - cJSON *req_params_downstream = NULL; - ks_bool_t downstream = KS_FALSE; - cJSON *req_params_channels = NULL; - ks_bool_t masterlocal = KS_FALSE; - cJSON *res = NULL; - cJSON *res_result = NULL; - cJSON *res_result_subscribe_channels = NULL; - cJSON *res_result_failed_channels = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - pool = ks_pool_get(bh); - ks_assert(pool); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_command = cJSON_GetObjectItem(req_params, "command"); - if (!req_params_command) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe request missing 'command'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params command"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - command = (blade_rpcsubscribe_command_t)req_params_command->valueint; - switch (command) { - case BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_ADD: - case BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_REMOVE: break; - default: goto done; - } - - req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - if (!req_params_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe request missing 'protocol'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_subscriber_nodeid = cJSON_GetObjectCstr(req_params, "subscriber-nodeid"); - if (!req_params_subscriber_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe request missing 'subscriber-nodeid'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params subscriber-nodeid"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - // @todo this may not be required, may be able to assume direction based on the session the message is received from, if came from upstream - // then it is heading downstream, otherwise it is heading upstream - req_params_downstream = cJSON_GetObjectItem(req_params, "downstream"); - downstream = req_params_downstream && req_params_downstream->type == cJSON_True; - - req_params_channels = cJSON_GetObjectItem(req_params, "channels"); - - if (!req_params_channels) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe request missing 'channels'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params channels"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe request processing\n", blade_session_id_get(bs)); - - masterlocal = blade_routemgr_master_local(blade_handle_routemgr_get(bh)); - - if (masterlocal || blade_routemgr_local_check(blade_handle_routemgr_get(bh), req_params_subscriber_nodeid)) { - // @note This is normally handled by blade_handle_rpcsubscribe_raw() to ensure authorization removals are processed during the request path - // including on the node they start on, whether that is the master or the subscriber - if (command == BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_REMOVE) { - cJSON *channel = NULL; - cJSON_ArrayForEach(channel, req_params_channels) { - blade_subscriptionmgr_subscriber_remove(bh->subscriptionmgr, NULL, req_params_protocol, channel->valuestring, req_params_subscriber_nodeid); - } - } - - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - - cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); - cJSON_AddStringToObject(res_result, "subscriber-nodeid", req_params_subscriber_nodeid); - if (downstream) cJSON_AddTrueToObject(res_result, "downstream"); - - if (command == BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_ADD) { - // @note this can only be received by the master due to other validation logic in requests which prevents the master from sending a request to add a subscriber - cJSON *channel = NULL; - - cJSON_ArrayForEach(channel, req_params_channels) { - if (blade_mastermgr_protocol_channel_authorization_verify(bh->mastermgr, req_params_protocol, channel->valuestring, req_params_subscriber_nodeid)) { - blade_subscriptionmgr_subscriber_add(bh->subscriptionmgr, NULL, req_params_protocol, channel->valuestring, req_params_subscriber_nodeid); - if (!res_result_subscribe_channels) res_result_subscribe_channels = cJSON_CreateArray(); - cJSON_AddItemToArray(res_result_subscribe_channels, cJSON_CreateString(channel->valuestring)); - } else { - if (!res_result_failed_channels) res_result_failed_channels = cJSON_CreateArray(); - cJSON_AddItemToArray(res_result_failed_channels, cJSON_CreateString(channel->valuestring)); - } - } - } - - if (res_result_subscribe_channels) cJSON_AddItemToObject(res_result, "subscribe-channels", res_result_subscribe_channels); - if (res_result_failed_channels) cJSON_AddItemToObject(res_result, "failed-channels", res_result_failed_channels); - // @note unsubscribe-channels get handled during the request path, so the response handlers do not need to reiterate them for any forseeable reason, and if they are needed they - // could be pulled from the original request associated to the response - - // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, 0, NULL, NULL); - } else { - blade_rpcsubscribe_data_t *temp_data = (blade_rpcsubscribe_data_t *)ks_pool_alloc(pool, sizeof(blade_rpcsubscribe_data_t)); - temp_data->original_requestid = ks_pstrdup(pool, blade_rpc_request_messageid_get(brpcreq)); - ks_pool_set_cleanup(temp_data, NULL, blade_rpcsubscribe_data_cleanup); - - blade_handle_rpcsubscribe_raw(bh, command, req_params_protocol, req_params_channels, req_params_subscriber_nodeid, downstream, blade_rpcsubscribe_response_handler, temp_data); - } - -done: - - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return KS_FALSE; -} - -// blade.subscribe response handler -ks_bool_t blade_rpcsubscribe_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - ks_bool_t ret = KS_FALSE; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - blade_rpcsubscribe_data_t *temp_data = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - const char *res_result_protocol = NULL; - const char *res_result_subscriber_nodeid = NULL; - cJSON *res_result_downstream = NULL; - ks_bool_t downstream = KS_FALSE; - cJSON *res_result_subscribe_channels = NULL; - cJSON *res_result_failed_channels = NULL; - - ks_assert(brpcres); - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(bh->sessionmgr, blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - temp_data = (blade_rpcsubscribe_data_t *)data; - - res = blade_rpc_response_message_get(brpcres); - ks_assert(res); - - res_result = cJSON_GetObjectItem(res, "result"); - if (!res_result) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe response missing 'result' object\n", blade_session_id_get(bs)); - goto done; - } - - // @todo the following 2 fields, protocol, and subscriber-nodeid may not be required to carry in the response as they could be - // obtained from the original request tied to the response, change this later - res_result_protocol = cJSON_GetObjectCstr(res_result, "protocol"); - if (!res_result_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe response missing 'protocol'\n", blade_session_id_get(bs)); - goto done; - } - - res_result_subscriber_nodeid = cJSON_GetObjectCstr(res_result, "subscriber-nodeid"); - if (!res_result_subscriber_nodeid) { - ks_log(KS_LOG_DEBUG, "Session (%s) subscribe response missing 'subscriber-nodeid'\n", blade_session_id_get(bs)); - goto done; - } - - res_result_downstream = cJSON_GetObjectItem(res_result, "downstream"); - downstream = res_result_downstream && res_result_downstream->type == cJSON_True; - - res_result_subscribe_channels = cJSON_GetObjectItem(res_result, "subscribe-channels"); - res_result_failed_channels = cJSON_GetObjectItem(res_result, "failed-channels"); - - if (res_result_subscribe_channels) { - // @note only reach here when the master has responded to authorize subscriptions to channels, so all nodes along the path must - // add the subscriber - cJSON *channel = NULL; - blade_subscription_t *bsub = NULL; - - cJSON_ArrayForEach(channel, res_result_subscribe_channels) { - blade_subscriptionmgr_subscriber_add(bh->subscriptionmgr, &bsub, res_result_protocol, channel->valuestring, res_result_subscriber_nodeid); - // @note these will only get assigned on the last response, received by the subscriber - if (temp_data && temp_data->channel_callback) blade_subscription_callback_set(bsub, temp_data->channel_callback); - if (temp_data && temp_data->channel_data) blade_subscription_callback_data_set(bsub, temp_data->channel_data); - } - } - - // @note this will only happen on the last response, received by the subscriber - if (temp_data && temp_data->original_callback) ret = temp_data->original_callback(brpcres, temp_data->original_data); - - if (temp_data && temp_data->original_requestid) { - blade_session_t *relay = NULL; - if (downstream) { - if (!(relay = blade_sessionmgr_upstream_lookup(bh->sessionmgr))) { - goto done; - } - } else { - if (!(relay = blade_routemgr_route_lookup(bh->routemgr, res_result_subscriber_nodeid))) { - goto done; - } - } - - blade_rpc_response_raw_create(&res, &res_result, temp_data->original_requestid); - - cJSON_AddStringToObject(res_result, "protocol", res_result_protocol); - cJSON_AddStringToObject(res_result, "subscriber-nodeid", res_result_subscriber_nodeid); - if (downstream) cJSON_AddTrueToObject(res_result, "downstream"); - if (res_result_subscribe_channels) cJSON_AddItemToObject(res_result, "subscribe-channels", cJSON_Duplicate(res_result_subscribe_channels, 1)); - if (res_result_failed_channels) cJSON_AddItemToObject(res_result, "failed-channels", cJSON_Duplicate(res_result_failed_channels, 1)); - - blade_session_send(relay, res, 0, NULL, NULL); - - cJSON_Delete(res); - - blade_session_read_unlock(relay); - } - -done: - if (temp_data) ks_pool_free(&temp_data); - blade_session_read_unlock(bs); - return ret; -} - - -// blade.broadcast request generator -KS_DECLARE(ks_status_t) blade_handle_rpcbroadcast(blade_handle_t *bh, const char *protocol, const char *channel, const char *event, cJSON *params, blade_rpc_response_callback_t callback, void *data) -{ - ks_assert(bh); - ks_assert(protocol); - - return blade_subscriptionmgr_broadcast(bh->subscriptionmgr, BLADE_RPCBROADCAST_COMMAND_EVENT, NULL, protocol, channel, event, params, callback, data); -} - -// @todo blade_handle_rpcbroadcast_raw() to encapsulate adding subcommands to broadcast to support protocol removal, protocol channel removal, and normal event broadcast - -// blade.broadcast request handler -ks_bool_t blade_rpcbroadcast_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - ks_bool_t ret = KS_FALSE; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - cJSON *req_params_command = NULL; - blade_rpcbroadcast_command_t command = BLADE_RPCBROADCAST_COMMAND_NONE; - const char *req_params_protocol = NULL; - const char *req_params_channel = NULL; - const char *req_params_event = NULL; - cJSON *req_params_params = NULL; - blade_subscription_t *bsub = NULL; - blade_rpc_request_callback_t callback = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (!req_params) { - ks_log(KS_LOG_DEBUG, "Session (%s) broadcast request missing 'params' object\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params object"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - if (!req_params_protocol) { - ks_log(KS_LOG_DEBUG, "Session (%s) broadcast request missing 'protocol'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params protocol"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - - req_params_command = cJSON_GetObjectItem(req_params, "command"); - if (!req_params_command) { - ks_log(KS_LOG_DEBUG, "Session (%s) broadcast request missing 'command'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params command"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - command = (blade_rpcbroadcast_command_t)req_params_command->valueint; - switch (command) { - case BLADE_RPCBROADCAST_COMMAND_EVENT: - req_params_event = cJSON_GetObjectCstr(req_params, "event"); - if (!req_params_event) { - ks_log(KS_LOG_DEBUG, "Session (%s) broadcast request missing 'event'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params event"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - case BLADE_RPCBROADCAST_COMMAND_CHANNEL_REMOVE: - req_params_channel = cJSON_GetObjectCstr(req_params, "channel"); - if (!req_params_channel) { - ks_log(KS_LOG_DEBUG, "Session (%s) broadcast request missing 'channel'\n", blade_session_id_get(bs)); - blade_rpc_error_raw_create(&res, NULL, blade_rpc_request_messageid_get(brpcreq), -32602, "Missing params channel"); - blade_session_send(bs, res, 0, NULL, NULL); - goto done; - } - break; - case BLADE_RPCBROADCAST_COMMAND_PROTOCOL_REMOVE: break; - default: goto done; - } - - req_params_params = cJSON_GetObjectItem(req_params, "params"); - - if (!blade_session_loopback(bs)) blade_subscriptionmgr_broadcast(bh->subscriptionmgr, command, blade_session_id_get(bs), req_params_protocol, req_params_channel, req_params_event, req_params_params, NULL, NULL); - else if (command == BLADE_RPCBROADCAST_COMMAND_EVENT) { - bsub = blade_subscriptionmgr_subscription_lookup(bh->subscriptionmgr, req_params_protocol, req_params_channel); - if (bsub) { - callback = blade_subscription_callback_get(bsub); - if (callback) ret = callback(brpcreq, blade_subscription_callback_data_get(bsub)); - } - } - - // build the actual response finally - blade_rpc_response_raw_create(&res, &res_result, blade_rpc_request_messageid_get(brpcreq)); - - // @todo this is not neccessary, can obtain this from the original request - cJSON_AddStringToObject(res_result, "protocol", req_params_protocol); - if (req_params_channel) cJSON_AddStringToObject(res_result, "channel", req_params_channel); - if (req_params_event) cJSON_AddStringToObject(res_result, "event", req_params_event); - - // request was just received on a session that is already read locked, so we can assume the response goes back on the same session without further lookup - blade_session_send(bs, res, 0, NULL, NULL); - -done: - - if (res) cJSON_Delete(res); - if (bs) blade_session_read_unlock(bs); - - return ret; -} - - -KS_DECLARE(const char *) blade_rpcbroadcast_request_protocol_get(blade_rpc_request_t *brpcreq) -{ - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_params_protocol = NULL; - - ks_assert(brpcreq); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (req_params) req_params_protocol = cJSON_GetObjectCstr(req_params, "protocol"); - - return req_params_protocol; -} - -KS_DECLARE(const char *) blade_rpcbroadcast_request_channel_get(blade_rpc_request_t *brpcreq) -{ - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_params_channel = NULL; - - ks_assert(brpcreq); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (req_params) req_params_channel = cJSON_GetObjectCstr(req_params, "channel"); - - return req_params_channel; -} - -KS_DECLARE(const char *) blade_rpcbroadcast_request_event_get(blade_rpc_request_t *brpcreq) -{ - cJSON *req = NULL; - cJSON *req_params = NULL; - const char *req_params_event = NULL; - - ks_assert(brpcreq); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (req_params) req_params_event = cJSON_GetObjectCstr(req_params, "event"); - - return req_params_event; -} - -KS_DECLARE(cJSON *) blade_rpcbroadcast_request_params_get(blade_rpc_request_t *brpcreq) -{ - cJSON *req = NULL; - cJSON *req_params = NULL; - cJSON *req_params_params = NULL; - - ks_assert(brpcreq); - - req = blade_rpc_request_message_get(brpcreq); - ks_assert(req); - - req_params = cJSON_GetObjectItem(req, "params"); - if (req_params) req_params_params = cJSON_GetObjectItem(req_params, "params"); - - return req_params_params; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_subscription.c b/libs/libblade/src/blade_subscription.c deleted file mode 100644 index 19c6fdd5d1..0000000000 --- a/libs/libblade/src/blade_subscription.c +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_subscription_s { - const char *protocol; - const char *channel; - ks_hash_t *subscribers; - - blade_rpc_request_callback_t callback; - void *callback_data; -}; - - -static void blade_subscription_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_subscription_t *bsub = (blade_subscription_t *)ptr; - - ks_assert(bsub); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (bsub->protocol) ks_pool_free(&bsub->protocol); - if (bsub->channel) ks_pool_free(&bsub->channel); - if (bsub->subscribers) ks_hash_destroy(&bsub->subscribers); - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_subscription_create(blade_subscription_t **bsubP, ks_pool_t *pool, const char *protocol, const char *channel) -{ - blade_subscription_t *bsub = NULL; - - ks_assert(bsubP); - ks_assert(pool); - ks_assert(protocol); - ks_assert(channel); - - bsub = ks_pool_alloc(pool, sizeof(blade_subscription_t)); - bsub->protocol = ks_pstrdup(pool, protocol); - bsub->channel = ks_pstrdup(pool, channel); - - ks_hash_create(&bsub->subscribers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bsub->subscribers); - - ks_pool_set_cleanup(bsub, NULL, blade_subscription_cleanup); - - *bsubP = bsub; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_subscription_destroy(blade_subscription_t **bsubP) -{ - ks_assert(bsubP); - ks_assert(*bsubP); - - ks_pool_free(bsubP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_subscription_protocol_get(blade_subscription_t *bsub) -{ - ks_assert(bsub); - - return bsub->protocol; -} - -KS_DECLARE(const char *) blade_subscription_channel_get(blade_subscription_t *bsub) -{ - ks_assert(bsub); - - return bsub->channel; -} - -KS_DECLARE(ks_hash_t *) blade_subscription_subscribers_get(blade_subscription_t *bsub) -{ - ks_assert(bsub); - - return bsub->subscribers; -} - -KS_DECLARE(ks_status_t) blade_subscription_subscribers_add(blade_subscription_t *bsub, const char *nodeid) -{ - char *key = NULL; - - ks_assert(bsub); - ks_assert(nodeid); - - key = ks_pstrdup(ks_pool_get(bsub), nodeid); - ks_hash_insert(bsub->subscribers, (void *)key, (void *)KS_TRUE); - - return KS_STATUS_SUCCESS; - -} - -KS_DECLARE(ks_status_t) blade_subscription_subscribers_remove(blade_subscription_t *bsub, const char *nodeid) -{ - ks_assert(bsub); - ks_assert(nodeid); - - ks_hash_remove(bsub->subscribers, (void *)nodeid); - - return KS_STATUS_SUCCESS; - -} - -KS_DECLARE(blade_rpc_request_callback_t) blade_subscription_callback_get(blade_subscription_t *bsub) -{ - ks_assert(bsub); - - return bsub->callback; -} - -KS_DECLARE(void) blade_subscription_callback_set(blade_subscription_t *bsub, blade_rpc_request_callback_t callback) -{ - ks_assert(bsub); - - bsub->callback = callback; -} - -KS_DECLARE(void *) blade_subscription_callback_data_get(blade_subscription_t *bsub) -{ - ks_assert(bsub); - - return bsub->callback_data; -} - -KS_DECLARE(void) blade_subscription_callback_data_set(blade_subscription_t *bsub, void *data) -{ - ks_assert(bsub); - - bsub->callback_data = data; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_subscriptionmgr.c b/libs/libblade/src/blade_subscriptionmgr.c deleted file mode 100644 index be25dae5b4..0000000000 --- a/libs/libblade/src/blade_subscriptionmgr.c +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_subscriptionmgr_s { - blade_handle_t *handle; - - ks_hash_t *subscriptions; // key, blade_subscription_t* - ks_hash_t *subscriptions_cleanup; // target, ks_hash_t* - -}; - - -static void blade_subscriptionmgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_routemgr_t *brmgr = (blade_routemgr_t *)ptr; - - //ks_assert(brmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_subscriptionmgr_create(blade_subscriptionmgr_t **bsmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_subscriptionmgr_t *bsmgr = NULL; - - ks_assert(bsmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - bsmgr = ks_pool_alloc(pool, sizeof(blade_subscriptionmgr_t)); - bsmgr->handle = bh; - - // @note can let removes free keys and values for subscriptions, both are allocated from the same pool as the hash itself - ks_hash_create(&bsmgr->subscriptions, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bsmgr->subscriptions); - - ks_hash_create(&bsmgr->subscriptions_cleanup, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bsmgr->subscriptions_cleanup); - - ks_pool_set_cleanup(bsmgr, NULL, blade_subscriptionmgr_cleanup); - - *bsmgrP = bsmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_subscriptionmgr_destroy(blade_subscriptionmgr_t **bsmgrP) -{ - blade_subscriptionmgr_t *bsmgr = NULL; - ks_pool_t *pool; - - ks_assert(bsmgrP); - ks_assert(*bsmgrP); - - bsmgr = *bsmgrP; - *bsmgrP = NULL; - - pool = ks_pool_get(bsmgr); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_subscriptionmgr_handle_get(blade_subscriptionmgr_t *bsmgr) -{ - ks_assert(bsmgr); - return bsmgr->handle; -} - -//KS_DECLARE(blade_session_t *) blade_subscriptionmgr_route_lookup(blade_routemgr_t *brmgr, const char *target) -//{ -// blade_session_t *bs = NULL; -// const char *router = NULL; -// -// ks_assert(brmgr); -// ks_assert(target); -// -// router = (const char *)ks_hash_search(brmgr->routes, (void *)target, KS_READLOCKED); -// if (router) bs = blade_handle_sessions_lookup(brmgr->handle, router); -// ks_hash_read_unlock(brmgr->routes); -// -// return bs; -//} - -KS_DECLARE(blade_subscription_t *) blade_subscriptionmgr_subscription_lookup(blade_subscriptionmgr_t *bsmgr, const char *protocol, const char *channel) -{ - blade_subscription_t *bsub = NULL; - char *key = NULL; - - ks_assert(bsmgr); - ks_assert(protocol); - ks_assert(channel); - - key = ks_psprintf(ks_pool_get(bsmgr), "%s:%s", protocol, channel); - - bsub = (blade_subscription_t *)ks_hash_search(bsmgr->subscriptions, (void *)key, KS_READLOCKED); - // @todo if (bsub) blade_subscription_read_lock(bsub); - ks_hash_read_unlock(bsmgr->subscriptions); - - ks_pool_free(&key); - - return bsub; -} - -KS_DECLARE(ks_status_t) blade_subscriptionmgr_subscription_remove(blade_subscriptionmgr_t *bsmgr, const char *protocol, const char *channel) -{ - ks_pool_t *pool = NULL; - char *bsub_key = NULL; - blade_subscription_t *bsub = NULL; - ks_hash_t *subscribers = NULL; - ks_hash_t *subscriptions = NULL; - - ks_assert(bsmgr); - ks_assert(protocol); - ks_assert(channel); - - pool = ks_pool_get(bsmgr); - - bsub_key = ks_psprintf(pool, "%s:%s", protocol, channel); - - ks_hash_write_lock(bsmgr->subscriptions); - - bsub = (blade_subscription_t *)ks_hash_search(bsmgr->subscriptions, (void *)bsub_key, KS_UNLOCKED); - - subscribers = blade_subscription_subscribers_get(bsub); - ks_assert(subscribers); - - for (ks_hash_iterator_t *it = ks_hash_first(subscribers, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - - subscriptions = (ks_hash_t *)ks_hash_search(bsmgr->subscriptions_cleanup, key, KS_UNLOCKED); - - ks_log(KS_LOG_DEBUG, "Subscriber Removed: %s from protocol %s, channel %s\n", key, protocol, channel); - ks_hash_remove(subscriptions, bsub_key); - - if (ks_hash_count(subscriptions) == 0) { - ks_hash_remove(bsmgr->subscriptions_cleanup, key); - } - } - - ks_log(KS_LOG_DEBUG, "Subscription Removed: %s from %s\n", channel, protocol); - ks_hash_remove(bsmgr->subscriptions, (void *)bsub_key); - - ks_hash_write_unlock(bsmgr->subscriptions); - - ks_pool_free(&bsub_key); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_bool_t) blade_subscriptionmgr_subscriber_add(blade_subscriptionmgr_t *bsmgr, blade_subscription_t **bsubP, const char *protocol, const char *channel, const char *subscriber) -{ - ks_pool_t *pool = NULL; - char *key = NULL; - blade_subscription_t *bsub = NULL; - ks_hash_t *bsub_cleanup = NULL; - ks_bool_t propagate = KS_FALSE; - - ks_assert(bsmgr); - ks_assert(protocol); - ks_assert(channel); - ks_assert(subscriber); - - pool = ks_pool_get(bsmgr); - - key = ks_psprintf(pool, "%s:%s", protocol, channel); - - ks_hash_write_lock(bsmgr->subscriptions); - - bsub = (blade_subscription_t *)ks_hash_search(bsmgr->subscriptions, (void *)key, KS_UNLOCKED); - - if (!bsub) { - blade_subscription_create(&bsub, pool, protocol, channel); - ks_assert(bsub); - - ks_hash_insert(bsmgr->subscriptions, (void *)ks_pstrdup(pool, key), (void *)bsub); - propagate = KS_TRUE; - } - - bsub_cleanup = (ks_hash_t *)ks_hash_search(bsmgr->subscriptions_cleanup, (void *)subscriber, KS_UNLOCKED); - if (!bsub_cleanup) { - ks_hash_create(&bsub_cleanup, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(bsub_cleanup); - - ks_log(KS_LOG_DEBUG, "Subscription Added: %s to %s\n", channel, protocol); - ks_hash_insert(bsmgr->subscriptions_cleanup, (void *)ks_pstrdup(pool, subscriber), (void *)bsub_cleanup); - } - ks_hash_insert(bsub_cleanup, (void *)ks_pstrdup(pool, key), (void *)KS_TRUE); - - blade_subscription_subscribers_add(bsub, subscriber); - - ks_hash_write_unlock(bsmgr->subscriptions); - - ks_log(KS_LOG_DEBUG, "Subscriber Added: %s to protocol %s, channel %s\n", subscriber, protocol, channel); - - ks_pool_free(&key); - - if (bsubP) *bsubP = bsub; - - return propagate; -} - -KS_DECLARE(ks_bool_t) blade_subscriptionmgr_subscriber_remove(blade_subscriptionmgr_t *bsmgr, blade_subscription_t **bsubP, const char *protocol, const char *channel, const char *subscriber) -{ - char *key = NULL; - blade_subscription_t *bsub = NULL; - ks_hash_t *bsub_cleanup = NULL; - ks_bool_t propagate = KS_FALSE; - - ks_assert(bsmgr); - ks_assert(protocol); - ks_assert(channel); - ks_assert(subscriber); - - key = ks_psprintf(ks_pool_get(bsmgr), "%s:%s", protocol, channel); - - ks_hash_write_lock(bsmgr->subscriptions); - - bsub = (blade_subscription_t *)ks_hash_search(bsmgr->subscriptions, (void *)key, KS_UNLOCKED); - - if (bsub) { - bsub_cleanup = (ks_hash_t *)ks_hash_search(bsmgr->subscriptions_cleanup, (void *)subscriber, KS_UNLOCKED); - if (bsub_cleanup) { - ks_hash_remove(bsub_cleanup, key); - - if (ks_hash_count(bsub_cleanup) == 0) { - ks_hash_remove(bsmgr->subscriptions_cleanup, (void *)subscriber); - } - - ks_log(KS_LOG_DEBUG, "Subscriber Removed: %s from protocol %s, channel %s\n", subscriber, protocol, channel); - blade_subscription_subscribers_remove(bsub, subscriber); - - if (ks_hash_count(blade_subscription_subscribers_get(bsub)) == 0) { - ks_log(KS_LOG_DEBUG, "Subscription Removed: %s from %s\n", channel, protocol); - ks_hash_remove(bsmgr->subscriptions, (void *)key); - propagate = KS_TRUE; - } - } - } - - ks_hash_write_unlock(bsmgr->subscriptions); - - ks_pool_free(&key); - - if (bsubP) *bsubP = bsub; - - return propagate; -} - -KS_DECLARE(void) blade_subscriptionmgr_purge(blade_subscriptionmgr_t *bsmgr, const char *target) -{ - ks_pool_t *pool = NULL; - ks_bool_t unsubbed = KS_FALSE; - - ks_assert(bsmgr); - ks_assert(target); - - pool = ks_pool_get(bsmgr); - - while (!unsubbed) { - ks_hash_t *subscriptions = NULL; - const char *protocol = NULL; - const char *channel = NULL; - - ks_hash_read_lock(bsmgr->subscriptions); - subscriptions = (ks_hash_t *)ks_hash_search(bsmgr->subscriptions_cleanup, (void *)target, KS_UNLOCKED); - if (!subscriptions) unsubbed = KS_TRUE; - else { - void *key = NULL; - void *value = NULL; - blade_subscription_t *bsub = NULL; - - ks_hash_iterator_t *it = ks_hash_first(subscriptions, KS_UNLOCKED); - ks_assert(it); - - ks_hash_this(it, (const void **)&key, NULL, &value); - - bsub = (blade_subscription_t *)ks_hash_search(bsmgr->subscriptions, key, KS_UNLOCKED); - ks_assert(bsub); - - // @note allocate these to avoid lifecycle issues when the last subscriber is removed causing the subscription to be removed - protocol = ks_pstrdup(pool, blade_subscription_protocol_get(bsub)); - channel = ks_pstrdup(pool, blade_subscription_channel_get(bsub)); - } - ks_hash_read_unlock(bsmgr->subscriptions); - - if (!unsubbed) { - blade_subscriptionmgr_subscriber_remove(bsmgr, NULL, protocol, channel, target); - - ks_pool_free(&protocol); - ks_pool_free(&channel); - } - } -} - -KS_DECLARE(ks_status_t) blade_subscriptionmgr_broadcast(blade_subscriptionmgr_t *bsmgr, blade_rpcbroadcast_command_t command, const char *excluded_sessionid, const char *protocol, const char *channel, const char *event, cJSON *params, blade_rpc_response_callback_t callback, void *data) -{ - ks_pool_t *pool = NULL; - const char *bsub_key = NULL; - blade_subscription_t *bsub = NULL; - blade_session_t *bs = NULL; - cJSON *req = NULL; - cJSON *req_params = NULL; - ks_hash_t *routers = NULL; - ks_hash_t *channels = NULL; - - ks_assert(bsmgr); - ks_assert(protocol); - - pool = ks_pool_get(bsmgr); - - switch (command) { - case BLADE_RPCBROADCAST_COMMAND_EVENT: - ks_assert(channel); - ks_assert(event); - case BLADE_RPCBROADCAST_COMMAND_CHANNEL_REMOVE: - ks_assert(channel); - bsub_key = ks_psprintf(pool, "%s:%s", protocol, channel); - - ks_hash_read_lock(bsmgr->subscriptions); - - bsub = (blade_subscription_t *)ks_hash_search(bsmgr->subscriptions, (void *)bsub_key, KS_UNLOCKED); - if (bsub) { - ks_hash_t *subscribers = blade_subscription_subscribers_get(bsub); - - ks_assert(subscribers); - - for (ks_hash_iterator_t *it = ks_hash_first(subscribers, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - - //if (excluded_nodeid && !ks_safe_strcasecmp(excluded_nodeid, (const char *)key)) continue; - - //if (blade_routemgr_local_check(blade_handle_routemgr_get(bsmgr->handle), (const char *)key)) continue; - - bs = blade_routemgr_route_lookup(blade_handle_routemgr_get(bsmgr->handle), (const char *)key); - if (bs) { - if (excluded_sessionid && !ks_safe_strcasecmp(excluded_sessionid, blade_session_id_get(bs))) continue; - if (!routers) ks_hash_create(&routers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - if (!ks_hash_search(routers, (void *)blade_session_id_get(bs), KS_UNLOCKED)) ks_hash_insert(routers, (void *)blade_session_id_get(bs), (void *)bs); - else blade_session_read_unlock(bs); - } - } - if (command == BLADE_RPCBROADCAST_COMMAND_CHANNEL_REMOVE) { - if (!channels) ks_hash_create(&channels, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - ks_hash_insert(channels, (void *)channel, (void *)KS_TRUE); - } - } - - ks_hash_read_unlock(bsmgr->subscriptions); - break; - case BLADE_RPCBROADCAST_COMMAND_PROTOCOL_REMOVE: - bsub_key = ks_pstrdup(pool, protocol); - - ks_hash_read_lock(bsmgr->subscriptions); - - for (ks_hash_iterator_t *it = ks_hash_first(bsmgr->subscriptions, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - - bsub = (blade_subscription_t *)value; - - if (ks_stristr(bsub_key, (const char *)key) == (const char *)key) { - ks_hash_t *subscribers = blade_subscription_subscribers_get(bsub); - - ks_assert(subscribers); - - for (ks_hash_iterator_t *it2 = ks_hash_first(subscribers, KS_UNLOCKED); it2; it2 = ks_hash_next(&it2)) { - void *key2 = NULL; - void *value2 = NULL; - - ks_hash_this(it2, (const void **)&key2, NULL, &value2); - - //if (excluded_nodeid && !ks_safe_strcasecmp(excluded_nodeid, (const char *)key2)) continue; - - //if (blade_routemgr_local_check(blade_handle_routemgr_get(bsmgr->handle), (const char *)key2)) continue; - - bs = blade_routemgr_route_lookup(blade_handle_routemgr_get(bsmgr->handle), (const char *)key2); - if (bs) { - if (excluded_sessionid && !ks_safe_strcasecmp(excluded_sessionid, blade_session_id_get(bs))) continue; - if (!routers) ks_hash_create(&routers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - if (!ks_hash_search(routers, (void *)blade_session_id_get(bs), KS_UNLOCKED)) ks_hash_insert(routers, (void *)blade_session_id_get(bs), (void *)bs); - else blade_session_read_unlock(bs); - } - } - - if (!channels) ks_hash_create(&channels, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - ks_hash_insert(channels, (void *)blade_subscription_channel_get(bsub), (void *)KS_TRUE); - } - } - - ks_hash_read_unlock(bsmgr->subscriptions); - break; - default: return KS_STATUS_ARG_INVALID; - } - - - bs = blade_sessionmgr_upstream_lookup(blade_handle_sessionmgr_get(bsmgr->handle)); - if (bs) { - if (!excluded_sessionid || ks_safe_strcasecmp(excluded_sessionid, blade_session_id_get(bs))) { - if (!routers) ks_hash_create(&routers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, pool); - ks_hash_insert(routers, (void *)blade_session_id_get(bs), (void *)bs); - } - else blade_session_read_unlock(bs); - } - - if (channels) { - for (ks_hash_iterator_t *it = ks_hash_first(channels, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - - blade_subscriptionmgr_subscription_remove(bsmgr, protocol, (const char *)key); - } - ks_hash_destroy(&channels); - } - - if (routers) { - for (ks_hash_iterator_t *it = ks_hash_first(routers, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - - bs = (blade_session_t *)value; - - blade_rpc_request_raw_create(pool, &req, &req_params, NULL, "blade.broadcast"); - cJSON_AddNumberToObject(req_params, "command", command); - cJSON_AddStringToObject(req_params, "protocol", protocol); - if (channel) cJSON_AddStringToObject(req_params, "channel", channel); - if (event) cJSON_AddStringToObject(req_params, "event", event); - if (params) cJSON_AddItemToObject(req_params, "params", cJSON_Duplicate(params, 1)); - - ks_log(KS_LOG_DEBUG, "Broadcasting: protocol %s, channel %s through %s\n", protocol, channel, blade_session_id_get(bs)); - - blade_session_send(bs, req, 0, callback, data); - - cJSON_Delete(req); - - blade_session_read_unlock(bs); - } - ks_hash_destroy(&routers); - } - - ks_pool_free(&bsub_key); - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_transport.c b/libs/libblade/src/blade_transport.c deleted file mode 100644 index fc30e0eff4..0000000000 --- a/libs/libblade/src/blade_transport.c +++ /dev/null @@ -1,137 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_transport_s { - blade_handle_t *handle; - - const char *name; - void *data; - blade_transport_callbacks_t *callbacks; -}; - - -static void blade_transport_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_transport_t *bt = (blade_transport_t *)ptr; - - //ks_assert(bt); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_transport_create(blade_transport_t **btP, blade_handle_t *bh, ks_pool_t *pool, const char *name, void *data, blade_transport_callbacks_t *callbacks) -{ - blade_transport_t *bt = NULL; - - ks_assert(btP); - ks_assert(bh); - ks_assert(pool); - ks_assert(name); - ks_assert(callbacks); - - bt = ks_pool_alloc(pool, sizeof(blade_transport_t)); - bt->handle = bh; - bt->name = ks_pstrdup(pool, name); - bt->data = data; - bt->callbacks = callbacks; - - ks_pool_set_cleanup(bt, NULL, blade_transport_cleanup); - - ks_log(KS_LOG_DEBUG, "Created transport %s\n", name); - - *btP = bt; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_transport_destroy(blade_transport_t **btP) -{ - blade_transport_t *bt = NULL; - ks_pool_t *pool = NULL; - - ks_assert(btP); - ks_assert(*btP); - - bt = *btP; - *btP = NULL; - - pool = ks_pool_get(bt); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_transport_handle_get(blade_transport_t *bt) -{ - ks_assert(bt); - return bt->handle; -} - -KS_DECLARE(const char *) blade_transport_name_get(blade_transport_t *bt) -{ - ks_assert(bt); - return bt->name; -} - -KS_DECLARE(void *) blade_transport_data_get(blade_transport_t *bt) -{ - ks_assert(bt); - return bt->data; -} - -KS_DECLARE(blade_transport_callbacks_t *) blade_transport_callbacks_get(blade_transport_t *bt) -{ - ks_assert(bt); - return bt->callbacks; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_transport_wss.c b/libs/libblade/src/blade_transport_wss.c deleted file mode 100644 index 57aa2c9e02..0000000000 --- a/libs/libblade/src/blade_transport_wss.c +++ /dev/null @@ -1,1206 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -#define BLADE_MODULE_WSS_TRANSPORT_NAME "wss" -#define BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX 16 - -typedef struct blade_transport_wss_s blade_transport_wss_t; -typedef struct blade_transport_wss_link_s blade_transport_wss_link_t; - -struct blade_transport_wss_s { - blade_handle_t *handle; - blade_transport_t *transport; - blade_transport_callbacks_t *callbacks; - - const char *ssl_key; - const char *ssl_cert; - const char *ssl_chain; - ks_sockaddr_t endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX]; - ks_sockaddr_t endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX]; - int32_t endpoints_ipv4_length; - int32_t endpoints_ipv6_length; - int32_t endpoints_backlog; - const char *endpoints_ssl_key; - const char *endpoints_ssl_cert; - const char *endpoints_ssl_chain; - - volatile ks_bool_t shutdown; - - struct pollfd *listeners_poll; - int32_t listeners_count; -}; - -struct blade_transport_wss_link_s { - blade_transport_wss_t *transport; - - const char *session_id; - ks_socket_t sock; - kws_t *kws; - SSL_CTX *ssl; -}; - - - -ks_status_t blade_transport_wss_listen(blade_transport_wss_t *btwss, ks_sockaddr_t *addr); -void *blade_transport_wss_listeners_thread(ks_thread_t *thread, void *data); - - -ks_status_t blade_transport_wss_link_create(blade_transport_wss_link_t **btwsslP, ks_pool_t *pool, blade_transport_wss_t *btwss, ks_socket_t sock, const char *session_id); - -ks_status_t blade_transport_wss_onstartup(blade_transport_t *bt, config_setting_t *config); -ks_status_t blade_transport_wss_onshutdown(blade_transport_t *bt); - -ks_status_t blade_transport_wss_onconnect(blade_connection_t **bcP, blade_transport_t *bt, blade_identity_t *target, const char *session_id); - -ks_status_t blade_transport_wss_onsend(blade_connection_t *bc, cJSON *json); -ks_status_t blade_transport_wss_onreceive(blade_connection_t *bc, cJSON **json); - -blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition); -blade_connection_state_hook_t blade_transport_wss_onstate_startup_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition); -blade_connection_state_hook_t blade_transport_wss_onstate_shutdown(blade_connection_t *bc, blade_connection_state_condition_t condition); -blade_connection_state_hook_t blade_transport_wss_onstate_run_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition); -blade_connection_state_hook_t blade_transport_wss_onstate_run_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition); - - - -static blade_transport_callbacks_t g_transport_wss_callbacks = -{ - blade_transport_wss_onstartup, - blade_transport_wss_onshutdown, - - blade_transport_wss_onconnect, - - blade_transport_wss_onsend, - blade_transport_wss_onreceive, - - blade_transport_wss_onstate_startup_inbound, - blade_transport_wss_onstate_startup_outbound, - blade_transport_wss_onstate_shutdown, - blade_transport_wss_onstate_shutdown, - blade_transport_wss_onstate_run_inbound, - blade_transport_wss_onstate_run_outbound, -}; - - -static void blade_transport_wss_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_transport_wss_t *btwss = (blade_transport_wss_t *)ptr; - - //ks_assert(btwss); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_transport_wss_create(blade_transport_t **btP, blade_handle_t *bh) -{ - blade_transport_wss_t *btwss = NULL; - ks_pool_t *pool = NULL; - - ks_assert(btP); - ks_assert(bh); - - ks_pool_open(&pool); - ks_assert(pool); - - btwss = ks_pool_alloc(pool, sizeof(blade_transport_wss_t)); - btwss->handle = bh; - - blade_transport_create(&btwss->transport, bh, pool, BLADE_MODULE_WSS_TRANSPORT_NAME, btwss, &g_transport_wss_callbacks); - btwss->callbacks = &g_transport_wss_callbacks; - - ks_pool_set_cleanup(btwss, NULL, blade_transport_wss_cleanup); - - ks_log(KS_LOG_DEBUG, "Created\n"); - - *btP = btwss->transport; - - return KS_STATUS_SUCCESS; -} - -static void blade_transport_wss_link_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_transport_wss_link_t *btwssl = (blade_transport_wss_link_t *)ptr; - - ks_assert(btwssl); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (btwssl->session_id) ks_pool_free(&btwssl->session_id); - if (btwssl->kws) kws_destroy(&btwssl->kws); - else ks_socket_close(&btwssl->sock); - if (btwssl->ssl) SSL_CTX_free(btwssl->ssl); - break; - case KS_MPCL_DESTROY: - break; - } -} - - -ks_status_t blade_transport_wss_link_create(blade_transport_wss_link_t **btwsslP, ks_pool_t *pool, blade_transport_wss_t *btwss, ks_socket_t sock, const char *session_id) -{ - blade_transport_wss_link_t *btwssl = NULL; - - ks_assert(btwsslP); - ks_assert(btwss); - ks_assert(sock != KS_SOCK_INVALID); - - btwssl = ks_pool_alloc(pool, sizeof(blade_transport_wss_link_t)); - btwssl->transport = btwss; - btwssl->sock = sock; - if (session_id) btwssl->session_id = ks_pstrdup(pool, session_id); - - ks_pool_set_cleanup(btwssl, NULL, blade_transport_wss_link_cleanup); - - ks_log(KS_LOG_DEBUG, "Created\n"); - - *btwsslP = btwssl; - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_transport_wss_link_ssl_init(blade_transport_wss_link_t *btwssl, ks_bool_t server) -{ - const SSL_METHOD *method = NULL; - const char *key = NULL; - const char *cert = NULL; - const char *chain = NULL; - - ks_assert(btwssl); - - method = server ? TLSv1_2_server_method() : TLSv1_2_client_method(); - key = server ? btwssl->transport->endpoints_ssl_key : btwssl->transport->ssl_key; - cert = server ? btwssl->transport->endpoints_ssl_cert : btwssl->transport->ssl_cert; - chain = server ? btwssl->transport->endpoints_ssl_chain : btwssl->transport->ssl_chain; - - // @todo should actually error out if there is no key/cert/chain available, as SSL/TLS is meant to be mandatory - if (key && cert) { - btwssl->ssl = SSL_CTX_new(method); - - // @todo probably manage this through configuration, but TLS 1.2 is preferred - SSL_CTX_set_options(btwssl->ssl, SSL_OP_NO_SSLv2); - SSL_CTX_set_options(btwssl->ssl, SSL_OP_NO_SSLv3); - SSL_CTX_set_options(btwssl->ssl, SSL_OP_NO_TLSv1); - SSL_CTX_set_options(btwssl->ssl, SSL_OP_NO_TLSv1_1); - // @todo look into difference in debian vs windows OpenSSL, aparantly debian system package does not provide this definition - //SSL_CTX_set_options(btwssl->ssl, SSL_OP_NO_DTLSv1); - SSL_CTX_set_options(btwssl->ssl, SSL_OP_NO_COMPRESSION); - if (server) SSL_CTX_set_verify(btwssl->ssl, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, NULL); - - if (chain) { - if (!SSL_CTX_use_certificate_chain_file(btwssl->ssl, chain)) { - ks_log(KS_LOG_DEBUG, "SSL Chain File Error\n"); - return KS_STATUS_FAIL; - } - if (!SSL_CTX_load_verify_locations(btwssl->ssl, chain, NULL)) { - ks_log(KS_LOG_DEBUG, "SSL Verify File Error\n"); - return KS_STATUS_FAIL; - } - } - - if (!SSL_CTX_use_certificate_file(btwssl->ssl, cert, SSL_FILETYPE_PEM)) { - ks_log(KS_LOG_DEBUG, "SSL Cert File Error\n"); - return KS_STATUS_FAIL; - } - - if (!SSL_CTX_use_PrivateKey_file(btwssl->ssl, key, SSL_FILETYPE_PEM)) { - ks_log(KS_LOG_DEBUG, "SSL Key File Error\n"); - return KS_STATUS_FAIL; - } - - if (!SSL_CTX_check_private_key(btwssl->ssl)) { - ks_log(KS_LOG_DEBUG, "SSL Key File Verification Error\n"); - return KS_STATUS_FAIL; - } - - SSL_CTX_set_cipher_list(btwssl->ssl, "HIGH:!DSS:!aNULL@STRENGTH"); - } - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_transport_wss_config(blade_transport_wss_t *btwss, config_setting_t *config) -{ - ks_pool_t *pool = NULL; - config_setting_t *transport = NULL; - config_setting_t *transport_wss = NULL; - config_setting_t *transport_wss_ssl = NULL; - config_setting_t *transport_wss_endpoints = NULL; - config_setting_t *transport_wss_endpoints_ipv4 = NULL; - config_setting_t *transport_wss_endpoints_ipv6 = NULL; - config_setting_t *transport_wss_endpoints_ssl = NULL; - config_setting_t *element; - config_setting_t *tmp1; - config_setting_t *tmp2; - const char *ssl_key = NULL; - const char *ssl_cert = NULL; - const char *ssl_chain = NULL; - ks_sockaddr_t endpoints_ipv4[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX]; - ks_sockaddr_t endpoints_ipv6[BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX]; - int32_t endpoints_ipv4_length = 0; - int32_t endpoints_ipv6_length = 0; - int32_t endpoints_backlog = 8; - const char *endpoints_ssl_key = NULL; - const char *endpoints_ssl_cert = NULL; - const char *endpoints_ssl_chain = NULL; - - ks_assert(btwss); - ks_assert(config); - - pool = ks_pool_get(btwss); - - if (!config_setting_is_group(config)) { - ks_log(KS_LOG_DEBUG, "!config_setting_is_group(config)\n"); - return KS_STATUS_FAIL; - } - transport = config_setting_get_member(config, "transport"); - if (transport) { - transport_wss = config_setting_get_member(transport, "wss"); - if (transport_wss) { - transport_wss_ssl = config_setting_get_member(transport_wss, "ssl"); - if (transport_wss_ssl) { - tmp1 = config_setting_get_member(transport_wss_ssl, "key"); - if (tmp1) ssl_key = config_setting_get_string(tmp1); - tmp1 = config_setting_get_member(transport_wss_ssl, "cert"); - if (tmp1) ssl_cert = config_setting_get_string(tmp1); - tmp1 = config_setting_get_member(transport_wss_ssl, "chain"); - if (tmp1) ssl_chain = config_setting_get_string(tmp1); - if (!ssl_key || !ssl_cert || !ssl_chain) return KS_STATUS_FAIL; - ks_log(KS_LOG_DEBUG, - "Using SSL: %s, %s, %s\n", - ssl_key, - ssl_cert, - ssl_chain); - } - - transport_wss_endpoints = config_setting_get_member(transport_wss, "endpoints"); - if (transport_wss_endpoints) { - transport_wss_endpoints_ipv4 = config_setting_get_member(transport_wss_endpoints, "ipv4"); - transport_wss_endpoints_ipv6 = config_setting_get_member(transport_wss_endpoints, "ipv6"); - if (transport_wss_endpoints_ipv4) { - if (config_setting_type(transport_wss_endpoints_ipv4) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL; - if ((endpoints_ipv4_length = config_setting_length(transport_wss_endpoints_ipv4)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX) - return KS_STATUS_FAIL; - - for (int32_t index = 0; index < endpoints_ipv4_length; ++index) { - element = config_setting_get_elem(transport_wss_endpoints_ipv4, index); - tmp1 = config_setting_get_member(element, "address"); - tmp2 = config_setting_get_member(element, "port"); - if (!tmp1 || !tmp2) return KS_STATUS_FAIL; - if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL; - if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL; - - if (ks_addr_set(&endpoints_ipv4[index], - config_setting_get_string(tmp1), - config_setting_get_int(tmp2), - AF_INET) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL; - ks_log(KS_LOG_DEBUG, - "Binding to IPV4 %s on port %d\n", - ks_addr_get_host(&endpoints_ipv4[index]), - ks_addr_get_port(&endpoints_ipv4[index])); - } - } - if (transport_wss_endpoints_ipv6) { - if (config_setting_type(transport_wss_endpoints_ipv6) != CONFIG_TYPE_LIST) return KS_STATUS_FAIL; - if ((endpoints_ipv6_length = config_setting_length(transport_wss_endpoints_ipv6)) > BLADE_MODULE_WSS_ENDPOINTS_MULTIHOME_MAX) - return KS_STATUS_FAIL; - - for (int32_t index = 0; index < endpoints_ipv6_length; ++index) { - element = config_setting_get_elem(transport_wss_endpoints_ipv6, index); - tmp1 = config_setting_get_member(element, "address"); - tmp2 = config_setting_get_member(element, "port"); - if (!tmp1 || !tmp2) return KS_STATUS_FAIL; - if (config_setting_type(tmp1) != CONFIG_TYPE_STRING) return KS_STATUS_FAIL; - if (config_setting_type(tmp2) != CONFIG_TYPE_INT) return KS_STATUS_FAIL; - - - if (ks_addr_set(&endpoints_ipv6[index], - config_setting_get_string(tmp1), - config_setting_get_int(tmp2), - AF_INET6) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL; - ks_log(KS_LOG_DEBUG, - "Binding to IPV6 %s on port %d\n", - ks_addr_get_host(&endpoints_ipv6[index]), - ks_addr_get_port(&endpoints_ipv6[index])); - } - } - if (endpoints_ipv4_length + endpoints_ipv6_length <= 0) return KS_STATUS_FAIL; - tmp1 = config_setting_get_member(transport_wss_endpoints, "backlog"); - if (tmp1) { - if (config_setting_type(tmp1) != CONFIG_TYPE_INT) return KS_STATUS_FAIL; - endpoints_backlog = config_setting_get_int(tmp1); - } - transport_wss_endpoints_ssl = config_setting_get_member(transport_wss_endpoints, "ssl"); - if (transport_wss_endpoints_ssl) { - tmp1 = config_setting_get_member(transport_wss_endpoints_ssl, "key"); - if (tmp1) endpoints_ssl_key = config_setting_get_string(tmp1); - tmp1 = config_setting_get_member(transport_wss_endpoints_ssl, "cert"); - if (tmp1) endpoints_ssl_cert = config_setting_get_string(tmp1); - tmp1 = config_setting_get_member(transport_wss_endpoints_ssl, "chain"); - if (tmp1) endpoints_ssl_chain = config_setting_get_string(tmp1); - if (!endpoints_ssl_key || !endpoints_ssl_cert || !endpoints_ssl_chain) return KS_STATUS_FAIL; - ks_log(KS_LOG_DEBUG, - "Using Endpoint SSL: %s, %s, %s\n", - endpoints_ssl_key, - endpoints_ssl_cert, - endpoints_ssl_chain); - } - } - } - } - - - // Configuration is valid, now assign it to the variables that are used - // If the configuration was invalid, then this does not get changed - if (ssl_key) { - btwss->ssl_key = ks_pstrdup(pool, ssl_key); - btwss->ssl_cert = ks_pstrdup(pool, ssl_cert); - btwss->ssl_chain = ks_pstrdup(pool, ssl_chain); - } - - for (int32_t index = 0; index < endpoints_ipv4_length; ++index) - btwss->endpoints_ipv4[index] = endpoints_ipv4[index]; - for (int32_t index = 0; index < endpoints_ipv6_length; ++index) - btwss->endpoints_ipv6[index] = endpoints_ipv6[index]; - btwss->endpoints_ipv4_length = endpoints_ipv4_length; - btwss->endpoints_ipv6_length = endpoints_ipv6_length; - btwss->endpoints_backlog = endpoints_backlog; - if (endpoints_ssl_key) { - btwss->endpoints_ssl_key = ks_pstrdup(pool, endpoints_ssl_key); - btwss->endpoints_ssl_cert = ks_pstrdup(pool, endpoints_ssl_cert); - btwss->endpoints_ssl_chain = ks_pstrdup(pool, endpoints_ssl_chain); - } - - ks_log(KS_LOG_DEBUG, "Configured\n"); - - return KS_STATUS_SUCCESS; -} - - -ks_status_t blade_transport_wss_onstartup(blade_transport_t *bt, config_setting_t *config) -{ - blade_transport_wss_t *btwss = NULL; - - ks_assert(bt); - ks_assert(config); - - btwss = (blade_transport_wss_t *)blade_transport_data_get(bt); - - if (blade_transport_wss_config(btwss, config) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "blade_transport_wss_config failed\n"); - return KS_STATUS_FAIL; - } - - for (int32_t index = 0; index < btwss->endpoints_ipv4_length; ++index) { - if (blade_transport_wss_listen(btwss, &btwss->endpoints_ipv4[index]) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "blade_transport_wss_listen (v4) failed\n"); - return KS_STATUS_FAIL; - } - } - for (int32_t index = 0; index < btwss->endpoints_ipv6_length; ++index) { - if (blade_transport_wss_listen(btwss, &btwss->endpoints_ipv6[index]) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "blade_transport_wss_listen (v6) failed\n"); - return KS_STATUS_FAIL; - } - } - - - if (btwss->listeners_count > 0 && - ks_thread_pool_add_job(blade_handle_tpool_get(btwss->handle), blade_transport_wss_listeners_thread, btwss) != KS_STATUS_SUCCESS) { - // @todo error logging - return KS_STATUS_FAIL; - } - - ks_log(KS_LOG_DEBUG, "Started\n"); - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_transport_wss_onshutdown(blade_transport_t *bt) -{ - blade_transport_wss_t *btwss = NULL; - - ks_assert(bt); - - btwss = (blade_transport_wss_t *)blade_transport_data_get(bt); - - if (btwss->listeners_count > 0) { - btwss->shutdown = KS_TRUE; - while (btwss->shutdown) ks_sleep_ms(1); - } - - for (int32_t index = 0; index < btwss->listeners_count; ++index) { - ks_socket_t sock = btwss->listeners_poll[index].fd; - ks_socket_shutdown(sock, SHUT_RDWR); - ks_socket_close(&sock); - } - - ks_log(KS_LOG_DEBUG, "Stopped\n"); - - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_transport_wss_listen(blade_transport_wss_t *btwss, ks_sockaddr_t *addr) -{ - ks_socket_t listener = KS_SOCK_INVALID; - int32_t listener_index = -1; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(btwss); - ks_assert(addr); - - if ((listener = socket(addr->family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) { - ks_log(KS_LOG_DEBUG, "listener == KS_SOCK_INVALID\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - ks_socket_option(listener, SO_REUSEADDR, KS_TRUE); - ks_socket_option(listener, TCP_NODELAY, KS_TRUE); - if (addr->family == AF_INET6) ks_socket_option(listener, IPV6_V6ONLY, KS_TRUE); - - if (ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - if (listen(listener, btwss->endpoints_backlog) != 0) { - ks_log(KS_LOG_DEBUG, "listen(listener, backlog) != 0\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - listener_index = btwss->listeners_count++; - if (!btwss->listeners_poll) btwss->listeners_poll = (struct pollfd *)ks_pool_alloc(ks_pool_get(btwss), sizeof(struct pollfd) * btwss->listeners_count); - else btwss->listeners_poll = (struct pollfd *)ks_pool_resize(btwss->listeners_poll, sizeof(struct pollfd) * btwss->listeners_count); - ks_assert(btwss->listeners_poll); - btwss->listeners_poll[listener_index].fd = listener; - btwss->listeners_poll[listener_index].events = POLLIN; // | POLLERR; - - ks_log(KS_LOG_DEBUG, "Bound %s on port %d at index %d\n", ks_addr_get_host(addr), ks_addr_get_port(addr), listener_index); - -done: - if (ret != KS_STATUS_SUCCESS) { - if (listener != KS_SOCK_INVALID) { - ks_socket_shutdown(listener, SHUT_RDWR); - ks_socket_close(&listener); - } - } - return ret; -} - -void *blade_transport_wss_listeners_thread(ks_thread_t *thread, void *data) -{ - blade_transport_wss_t *btwss = NULL; - blade_transport_wss_link_t *btwssl = NULL; - blade_connection_t *bc = NULL; - - ks_assert(thread); - ks_assert(data); - - btwss = (blade_transport_wss_t *)data; - - ks_log(KS_LOG_DEBUG, "Started\n"); - while (!btwss->shutdown) { - // @todo take exact timeout from a setting in config_wss_endpoints - if (ks_poll(btwss->listeners_poll, btwss->listeners_count, 100) > 0) { - for (int32_t index = 0; index < btwss->listeners_count; ++index) { - ks_socket_t sock = KS_SOCK_INVALID; - - if (btwss->listeners_poll[index].revents & POLLERR) { - // @todo: error handling, just skip the listener for now, it might recover, could skip X times before closing? - ks_log(KS_LOG_DEBUG, "POLLERR on index %d\n", index); - continue; - } - if (!(btwss->listeners_poll[index].revents & POLLIN)) continue; - - if ((sock = accept(btwss->listeners_poll[index].fd, NULL, NULL)) == KS_SOCK_INVALID) { - // @todo: error handling, just skip the socket for now as most causes are because remote side became unreachable - ks_log(KS_LOG_DEBUG, "Accept failed on index %d\n", index); - continue; - } - - // @todo getsockname and getpeername (getpeername can be skipped if passing to accept instead) - - ks_log(KS_LOG_DEBUG, "Socket accepted\n", index); - - // @todo make new function to wrap the following code all the way through assigning initial state to reuse in outbound connects - blade_connection_create(&bc, btwss->handle); - ks_assert(bc); - - blade_transport_wss_link_create(&btwssl, ks_pool_get(bc), btwss, sock, NULL); - ks_assert(btwssl); - - blade_connection_transport_set(bc, btwssl, btwss->callbacks); - - blade_connection_read_lock(bc, KS_TRUE); - - if (blade_connection_startup(bc, BLADE_CONNECTION_DIRECTION_INBOUND) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Connection (%s) startup failed\n", blade_connection_id_get(bc)); - blade_connection_read_unlock(bc); - blade_connection_destroy(&bc); - continue; - } - ks_log(KS_LOG_DEBUG, "Connection (%s) started\n", blade_connection_id_get(bc)); - - blade_connectionmgr_connection_add(blade_handle_connectionmgr_get(btwss->handle), bc); - - blade_connection_state_set(bc, BLADE_CONNECTION_STATE_STARTUP); - - blade_connection_read_unlock(bc); - // @todo end of reusable function, lock ensures it cannot be destroyed until this code finishes - } - } - } - ks_log(KS_LOG_DEBUG, "Stopped\n"); - - btwss->shutdown = KS_FALSE; - - return NULL; -} - -ks_status_t blade_transport_wss_onconnect(blade_connection_t **bcP, blade_transport_t *bt, blade_identity_t *target, const char *session_id) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_transport_wss_t *btwss = NULL; - ks_sockaddr_t addr; - ks_socket_t sock = KS_SOCK_INVALID; - int family = AF_INET; - const char *ip = NULL; - const char *portstr = NULL; - ks_port_t port = 2100; - blade_transport_wss_link_t *btwssl = NULL; - blade_connection_t *bc = NULL; - - ks_assert(bcP); - ks_assert(bt); - ks_assert(target); - - btwss = (blade_transport_wss_t *)blade_transport_data_get(bt); - - *bcP = NULL; - - ks_log(KS_LOG_DEBUG, "Connect Callback: %s\n", blade_identity_uri_get(target)); - - // @todo completely rework all of this once more is known about connecting when an identity has no explicit transport details but this transport - // has been choosen anyway - ip = blade_identity_host_get(target); - portstr = blade_identity_port_get(target); - if (!ip) { - ks_log(KS_LOG_DEBUG, "No host provided\n"); - ret = KS_STATUS_FAIL; - goto done; - } - // @todo: this should detect IP's and fall back on DNS and/or SRV for hostname lookup, for the moment hosts must be IP's - - // @todo wrap this code to get address family from string IP between IPV4 and IPV6, and put it in libks somewhere - { - ks_size_t len = strlen(ip); - - if (len <= 3) { - ks_log(KS_LOG_DEBUG, "Invalid host provided\n"); - ret = KS_STATUS_FAIL; - goto done; - } - if (ip[1] == '.' || ip[2] == '.' || (len > 3 && ip[3] == '.')) family = AF_INET; - else family = AF_INET6; - } - - if (portstr) { - int p = atoi(portstr); - if (p > 0 && p <= UINT16_MAX) port = p; - } - - ks_log(KS_LOG_DEBUG, "Connecting to %s on port %d\n", ip, port); - - ks_addr_set(&addr, ip, port, family); - if ((sock = ks_socket_connect(SOCK_STREAM, IPPROTO_TCP, &addr)) == KS_SOCK_INVALID) { - // @todo: error handling, just fail for now as most causes are because remote side became unreachable - ks_log(KS_LOG_DEBUG, "Connect failed\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - ks_log(KS_LOG_DEBUG, "Socket connected\n"); - - // @todo see above listener code, make reusable function for the following code - blade_connection_create(&bc, btwss->handle); - ks_assert(bc); - - blade_transport_wss_link_create(&btwssl, ks_pool_get(bc), btwss, sock, session_id); - ks_assert(btwssl); - - blade_connection_transport_set(bc, btwssl, btwss->callbacks); - - blade_connection_read_lock(bc, KS_TRUE); - - if (blade_connection_startup(bc, BLADE_CONNECTION_DIRECTION_OUTBOUND) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Connection (%s) startup failed\n", blade_connection_id_get(bc)); - blade_connection_read_unlock(bc); - blade_connection_destroy(&bc); - ret = KS_STATUS_FAIL; - goto done; - } - ks_log(KS_LOG_DEBUG, "Connection (%s) started\n", blade_connection_id_get(bc)); - - blade_connectionmgr_connection_add(blade_handle_connectionmgr_get(btwss->handle), bc); - - blade_connection_state_set(bc, BLADE_CONNECTION_STATE_STARTUP); - - blade_connection_read_unlock(bc); - - // @todo consider ramification of unlocking above, while returning the new connection object back to the framework, thread might run and disconnect quickly - // @todo have blade_handle_connect and blade_transport_wss_on_connect (and the abstracted callback) return a copy of the connection id (allocated from blade_handle_t's pool temporarily) rather than the connection pointer itself - // which will then require getting the connection and thus relock it for any further use, if it disconnects during that time the connection will be locked preventing obtaining and then return NULL if removed - *bcP = bc; - - done: - return ret; -} - -ks_status_t blade_transport_wss_link_write(blade_transport_wss_link_t *btwssl, cJSON *json) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - char *json_str = NULL; - ks_size_t json_str_len = 0; - - ks_assert(btwssl); - ks_assert(json); - - json_str = cJSON_PrintUnformatted(json); - if (!json_str) { - ks_log(KS_LOG_DEBUG, "Failed to generate json string\n"); - ret = KS_STATUS_FAIL; - goto done; - } - // @todo determine if WSOC_TEXT null terminates when read_frame is called, or if it's safe to include like this - json_str_len = strlen(json_str) + 1; - if ((ks_size_t)kws_write_frame(btwssl->kws, WSOC_TEXT, json_str, json_str_len) != json_str_len) { - ks_log(KS_LOG_DEBUG, "Failed to write frame\n"); - ret = KS_STATUS_FAIL; - goto done; - } - ks_log(KS_LOG_DEBUG, "Frame written %d bytes\n", json_str_len); - - done: - if (json_str) free(json_str); - - return ret; -} - -ks_status_t blade_transport_wss_onsend(blade_connection_t *bc, cJSON *json) -{ - blade_transport_wss_link_t *btwssl = NULL; - - ks_assert(bc); - ks_assert(json); - - btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc); - - return blade_transport_wss_link_write(btwssl, json); -} - -ks_status_t blade_transport_wss_link_read(blade_transport_wss_link_t *btwssl, cJSON **json) -{ - // @todo get exact timeout from service config? - int32_t poll_flags = 0; - - ks_assert(btwssl); - ks_assert(json); - - poll_flags = ks_wait_sock(btwssl->sock, 1, KS_POLL_READ); // | KS_POLL_ERROR); - - *json = NULL; - - if (poll_flags & KS_POLL_ERROR) { - ks_log(KS_LOG_DEBUG, "POLLERR\n"); - return KS_STATUS_FAIL; - } - if (poll_flags & KS_POLL_READ) { - kws_opcode_t opcode; - uint8_t *frame_data = NULL; - ks_ssize_t frame_data_len = kws_read_frame(btwssl->kws, &opcode, &frame_data); - - if (frame_data_len <= 0) { - // @todo error logging, strerror(ks_errno()) - // 0 means socket closed with WS_NONE, which closes websocket with no additional reason - // -1 means socket closed with a general failure - // -2 means nonblocking wait - // other values are based on WS_XXX reasons - // negative values are based on reasons, except for -1 is but -2 is nonblocking wait, and - ks_log(KS_LOG_DEBUG, "Failed to read frame\n"); - return KS_STATUS_FAIL; - } - ks_log(KS_LOG_DEBUG, "Frame read %d bytes\n", frame_data_len); - - if (!(*json = cJSON_Parse((char *)frame_data))) { - ks_log(KS_LOG_DEBUG, "Failed to parse frame\n"); - return KS_STATUS_FAIL; - } - } - return KS_STATUS_SUCCESS; -} - -ks_status_t blade_transport_wss_onreceive(blade_connection_t *bc, cJSON **json) -{ - blade_transport_wss_link_t *btwssl = NULL; - - ks_assert(bc); - ks_assert(json); - - btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc); - - return blade_transport_wss_link_read(btwssl, json); -} - -ks_status_t blade_transport_wss_rpc_error_send(blade_connection_t *bc, const char *id, int32_t code, const char *message) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_transport_wss_link_t *btwssl = NULL; - cJSON *json = NULL; - - ks_assert(bc); - //ks_assert(id); - ks_assert(message); - - btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc); - - blade_rpc_error_raw_create(&json, NULL, id, code, message); - - if (blade_transport_wss_link_write(btwssl, json) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Failed to write error message\n"); - ret = KS_STATUS_FAIL; - } - - cJSON_Delete(json); - return ret; -} - - -blade_connection_state_hook_t blade_transport_wss_onstate_startup_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition) -{ - blade_connection_state_hook_t ret = BLADE_CONNECTION_STATE_HOOK_SUCCESS; - blade_transport_wss_link_t *btwssl = NULL; - cJSON *json_req = NULL; - cJSON *json_res = NULL; - cJSON *json_params = NULL; - cJSON *json_result = NULL; - //cJSON *error = NULL; - blade_session_t *bs = NULL; - blade_handle_t *bh = NULL; - const char *jsonrpc = NULL; - const char *id = NULL; - const char *method = NULL; - const char *sessionid = NULL; - uuid_t uuid; - const char *nodeid = NULL; - ks_time_t timeout; - - ks_assert(bc); - - bh = blade_connection_handle_get(bc); - ks_assert(bh); - - ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition); - - if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS; - - btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc); - - if (blade_transport_wss_link_ssl_init(btwssl, KS_TRUE) != KS_STATUS_SUCCESS) { - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - if (kws_init(&btwssl->kws, btwssl->sock, btwssl->ssl, NULL, KWS_BLOCK, ks_pool_get(btwssl)) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Failed websocket init\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - // @todo very temporary, really need monotonic clock and get timeout delay and sleep delay from config - timeout = ks_time_now() + (5 * KS_USEC_PER_SEC); - while (blade_transport_wss_link_read(btwssl, &json_req) == KS_STATUS_SUCCESS) { - if (json_req) break; - ks_sleep_ms(250); - if (ks_time_now() >= timeout) break; - } - - if (!json_req) { - ks_log(KS_LOG_DEBUG, "Failed to receive message before timeout\n"); - blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Timeout while expecting request"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - // @todo start here for a reusable handler for "blade.connect" request rpc method within transport implementations, - // output 2 parameters for response and error, if an error occurs, send it, otherwise send the response - - jsonrpc = cJSON_GetObjectCstr(json_req, "jsonrpc"); // @todo check for definitions of these keys and fixed values - if (!jsonrpc || strcmp(jsonrpc, "2.0")) { - ks_log(KS_LOG_DEBUG, "Received message is not the expected protocol\n"); - blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'jsonrpc' field"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - id = cJSON_GetObjectCstr(json_req, "id"); - if (!id) { - ks_log(KS_LOG_DEBUG, "Received message is missing 'id'\n"); - blade_transport_wss_rpc_error_send(bc, NULL, -32600, "Invalid request, missing 'id' field"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - method = cJSON_GetObjectCstr(json_req, "method"); - if (!method || strcasecmp(method, "blade.connect")) { - ks_log(KS_LOG_DEBUG, "Received message is missing 'method' or is an unexpected method\n"); - blade_transport_wss_rpc_error_send(bc, id, -32601, "Missing or unexpected 'method' field"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - json_params = cJSON_GetObjectItem(json_req, "params"); - if (json_params) { - sessionid = cJSON_GetObjectCstr(json_params, "sessionid"); - if (sessionid) { - ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", sessionid); - } - } - - ks_uuid(&uuid); - nodeid = ks_uuid_str(ks_pool_get(bc), &uuid); - - if (sessionid) { - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), sessionid); - if (bs) { - if (blade_session_terminating(bs)) { - blade_session_read_unlock(bs); - ks_log(KS_LOG_DEBUG, "Session (%s) terminating\n", blade_session_id_get(bs)); - bs = NULL; - } else { - ks_log(KS_LOG_DEBUG, "Session (%s) located\n", blade_session_id_get(bs)); - // @todo validate against IP address or something to ensure reconnects are acceptable - } - } - } - - if (!bs) { - blade_session_create(&bs, bh, BLADE_SESSION_FLAGS_NONE, NULL); - ks_assert(bs); - - sessionid = blade_session_id_get(bs); - ks_log(KS_LOG_DEBUG, "Session (%s) created\n", sessionid); - - blade_session_read_lock(bs, KS_TRUE); // this will be done by blade_handle_sessions_get() otherwise - - if (blade_session_startup(bs) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", sessionid); - blade_transport_wss_rpc_error_send(bc, id, -32603, "Internal error, session could not be started"); - blade_session_read_unlock(bs); - blade_session_destroy(&bs); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - // This is an inbound connection, thus it is always creating a downstream session - - ks_log(KS_LOG_DEBUG, "Session (%s) started\n", sessionid); - blade_sessionmgr_session_add(blade_handle_sessionmgr_get(bh), bs); - - // This is primarily to cleanup the routes added to the blade_handle for main routing when a session terminates, these don't have a lot of use otherwise but it will keep the main route table - // from having long running write locks when a session cleans up - blade_session_route_add(bs, nodeid); - // This is the main routing entry to make an identity routable through a session when a message is received for a given identity in this table, these allow to efficiently determine which session - // a message should pass through when it does not match the local node id from blade_routemgr_t, and must be matched with a call to blade_session_route_add() for cleanup, additionally when - // a "blade.route" is received the identity it carries affects these routes along with the sessionid of the downstream session it came through, and "blade.route" would also - // result in the new identities being added as routes however federation registration would require a special process to maintain proper routing - blade_routemgr_route_add(blade_handle_routemgr_get(bh), nodeid, sessionid); - } - - blade_rpc_response_raw_create(&json_res, &json_result, id); - ks_assert(json_res); - - cJSON_AddStringToObject(json_result, "sessionid", sessionid); - cJSON_AddStringToObject(json_result, "nodeid", nodeid); - - if (!blade_routemgr_master_pack(blade_handle_routemgr_get(bh), json_result, "master-nodeid")) { - ks_log(KS_LOG_DEBUG, "Master nodeid unavailable, upstream is not established\n"); - blade_transport_wss_rpc_error_send(bc, id, -32602, "Master nodeid unavailable"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - // This starts the final process for associating the connection to the session, including for reconnecting to an existing session, this simply - // associates the session to this connection, upon return the remainder of the association for the session to the connection is handled along - // with making sure both this connection and the session state machines are in running states - blade_connection_session_set(bc, sessionid); - - // @todo end of reusable handler for "blade.connect" request - - if (blade_transport_wss_link_write(btwssl, json_res) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Failed to write response message\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - done: - // @note the state machine expects if we return SUCCESS, that the session assigned to the connection will be read locked to ensure that the state - // machine can finish attaching the session, if you BYPASS then you can handle everything here in the callback, but this should be fairly standard - // behaviour to simply go as far as assigning a session to the connection and let the system handle the rest - if (json_req) cJSON_Delete(json_req); - if (json_res) cJSON_Delete(json_res); - - return ret; -} - -blade_connection_state_hook_t blade_transport_wss_onstate_startup_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition) -{ - blade_connection_state_hook_t ret = BLADE_CONNECTION_STATE_HOOK_SUCCESS; - blade_handle_t *bh = NULL; - blade_transport_wss_link_t *btwssl = NULL; - ks_pool_t *pool = NULL; - cJSON *json_req = NULL; - cJSON *json_params = NULL; - cJSON *json_res = NULL; - const char *mid = NULL; - ks_time_t timeout; - const char *jsonrpc = NULL; - const char *id = NULL; - cJSON *json_error = NULL; - cJSON *json_result = NULL; - const char *sessionid = NULL; - const char *nodeid = NULL; - const char *master_nodeid = NULL; - blade_session_t *bs = NULL; - - ks_assert(bc); - - ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition); - - if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS; - - bh = blade_connection_handle_get(bc); - btwssl = (blade_transport_wss_link_t *)blade_connection_transport_get(bc); - pool = ks_pool_get(bh); - - if (blade_transport_wss_link_ssl_init(btwssl, KS_FALSE) != KS_STATUS_SUCCESS) { - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - if (kws_init(&btwssl->kws, btwssl->sock, btwssl->ssl, "/blade:blade.invalid:blade", KWS_BLOCK, ks_pool_get(btwssl)) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Failed websocket init\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - blade_rpc_request_raw_create(pool, &json_req, &json_params, &mid, "blade.connect"); - ks_assert(json_req); - - if (btwssl->session_id) cJSON_AddStringToObject(json_params, "sessionid", btwssl->session_id); - - ks_log(KS_LOG_DEBUG, "Session (%s) requested\n", (btwssl->session_id ? btwssl->session_id : "none")); - - if (blade_transport_wss_link_write(btwssl, json_req) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Failed to write request message\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - - timeout = ks_time_now() + (5 * KS_USEC_PER_SEC); - while (blade_transport_wss_link_read(btwssl, &json_res) == KS_STATUS_SUCCESS) { - if (json_res) break; - ks_sleep_ms(250); - if (ks_time_now() >= timeout) break; - } - - if (!json_res) { - ks_log(KS_LOG_DEBUG, "Failed to receive message before timeout\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - // @todo start here for a reusable handler for "blade.connect" response rpc method within transport implementations - - jsonrpc = cJSON_GetObjectCstr(json_res, "jsonrpc"); // @todo check for definitions of these keys and fixed values - if (!jsonrpc || strcmp(jsonrpc, "2.0")) { - ks_log(KS_LOG_DEBUG, "Received message is not the expected protocol\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - id = cJSON_GetObjectCstr(json_res, "id"); // @todo switch to number if we are not using a uuid for message id - if (!id || strcasecmp(mid, id)) { - ks_log(KS_LOG_DEBUG, "Received message has missing or unexpected 'id'\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - json_error = cJSON_GetObjectItem(json_res, "error"); - if (json_error) { - ks_log(KS_LOG_DEBUG, "Error message ... add the details\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - json_result = cJSON_GetObjectItem(json_res, "result"); - if (!json_result) { - ks_log(KS_LOG_DEBUG, "Received message is missing 'result'\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - sessionid = cJSON_GetObjectCstr(json_result, "sessionid"); - if (!sessionid) { - ks_log(KS_LOG_DEBUG, "Received message 'result' is missing 'sessionid'\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - nodeid = cJSON_GetObjectCstr(json_result, "nodeid"); - if (!nodeid) { - ks_log(KS_LOG_DEBUG, "Received message 'result' is missing 'nodeid'\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - master_nodeid = cJSON_GetObjectCstr(json_result, "master-nodeid"); - if (!master_nodeid) { - ks_log(KS_LOG_DEBUG, "Received message 'result' is missing 'master-nodeid'\n"); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - bs = blade_sessionmgr_upstream_lookup(blade_handle_sessionmgr_get(bh)); - if (bs) { - if (ks_safe_strcasecmp(blade_session_id_get(bs), sessionid)) { - ks_log(KS_LOG_DEBUG, "Already have upstream session with different sessionid, could not establish session\n"); - blade_session_read_unlock(bs); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - ks_log(KS_LOG_DEBUG, "Session (%s) reestablishing\n", blade_session_id_get(bs)); - } - - if (!bs) { - blade_session_create(&bs, bh, BLADE_SESSION_FLAGS_UPSTREAM, sessionid); - ks_assert(bs); - - ks_log(KS_LOG_DEBUG, "Session (%s) created\n", blade_session_id_get(bs)); - - blade_session_read_lock(bs, KS_TRUE); // this will be done by blade_handle_sessions_get() otherwise - - if (blade_session_startup(bs) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "Session (%s) startup failed\n", blade_session_id_get(bs)); - blade_session_read_unlock(bs); - blade_session_destroy(&bs); - ret = BLADE_CONNECTION_STATE_HOOK_DISCONNECT; - goto done; - } - - // This is an outbound connection, thus it is always creating an upstream session - ks_log(KS_LOG_DEBUG, "Session (%s) started\n", blade_session_id_get(bs)); - blade_sessionmgr_session_add(blade_handle_sessionmgr_get(bh), bs); - - blade_routemgr_local_set(blade_handle_routemgr_get(bh), nodeid); - blade_routemgr_master_set(blade_handle_routemgr_get(bh), master_nodeid); - } - - blade_connection_session_set(bc, blade_session_id_get(bs)); - - // @todo end of reusable handler for "blade.connect" response - - done: - if (json_req) cJSON_Delete(json_req); - if (json_res) cJSON_Delete(json_res); - - return ret; -} - -blade_connection_state_hook_t blade_transport_wss_onstate_shutdown(blade_connection_t *bc, blade_connection_state_condition_t condition) -{ - ks_assert(bc); - - ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition); - - if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) return BLADE_CONNECTION_STATE_HOOK_SUCCESS; - - return BLADE_CONNECTION_STATE_HOOK_SUCCESS; -} - -blade_connection_state_hook_t blade_transport_wss_onstate_run_inbound(blade_connection_t *bc, blade_connection_state_condition_t condition) -{ - ks_assert(bc); - - if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) { - ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition); - } - - return BLADE_CONNECTION_STATE_HOOK_SUCCESS; -} - -blade_connection_state_hook_t blade_transport_wss_onstate_run_outbound(blade_connection_t *bc, blade_connection_state_condition_t condition) -{ - ks_assert(bc); - - if (condition == BLADE_CONNECTION_STATE_CONDITION_PRE) { - ks_log(KS_LOG_DEBUG, "State Callback: %d\n", (int32_t)condition); - } - - return BLADE_CONNECTION_STATE_HOOK_SUCCESS; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_transportmgr.c b/libs/libblade/src/blade_transportmgr.c deleted file mode 100644 index 0f723a3f52..0000000000 --- a/libs/libblade/src/blade_transportmgr.c +++ /dev/null @@ -1,233 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_transportmgr_s { - blade_handle_t *handle; - - ks_hash_t *transports; // name, blade_transport_t* - blade_transport_t *default_transport; // default wss transport -}; - - -static void blade_transportmgr_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_transportmgr_t *btmgr = (blade_transportmgr_t *)ptr; - ks_hash_iterator_t *it = NULL; - - ks_assert(btmgr); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - while ((it = ks_hash_first(btmgr->transports, KS_UNLOCKED)) != NULL) { - void *key = NULL; - blade_transport_t *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - ks_hash_remove(btmgr->transports, key); - - blade_transport_destroy(&value); // must call destroy to close the transport pool, using FREE_VALUE on the hash would attempt to free the transport from the wrong pool - } - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_transportmgr_create(blade_transportmgr_t **btmgrP, blade_handle_t *bh) -{ - ks_pool_t *pool = NULL; - blade_transportmgr_t *btmgr = NULL; - - ks_assert(btmgrP); - - ks_pool_open(&pool); - ks_assert(pool); - - btmgr = ks_pool_alloc(pool, sizeof(blade_transportmgr_t)); - btmgr->handle = bh; - - ks_hash_create(&btmgr->transports, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_assert(btmgr->transports); - - ks_pool_set_cleanup(btmgr, NULL, blade_transportmgr_cleanup); - - *btmgrP = btmgr; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_transportmgr_destroy(blade_transportmgr_t **btmgrP) -{ - blade_transportmgr_t *btmgr = NULL; - ks_pool_t *pool; - - ks_assert(btmgrP); - ks_assert(*btmgrP); - - btmgr = *btmgrP; - *btmgrP = NULL; - - pool = ks_pool_get(btmgr); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_transportmgr_startup(blade_transportmgr_t *btmgr, config_setting_t *config) -{ - ks_assert(btmgr); - - for (ks_hash_iterator_t *it = ks_hash_first(btmgr->transports, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - blade_transport_t *value = NULL; - blade_transport_callbacks_t *callbacks = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - callbacks = blade_transport_callbacks_get(value); - ks_assert(callbacks); - - if (callbacks->onstartup) callbacks->onstartup(value, config); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_transportmgr_shutdown(blade_transportmgr_t *btmgr) -{ - ks_assert(btmgr); - - ks_hash_read_lock(btmgr->transports); - for (ks_hash_iterator_t *it = ks_hash_first(btmgr->transports, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - blade_transport_t *value = NULL; - blade_transport_callbacks_t *callbacks = NULL; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - callbacks = blade_transport_callbacks_get(value); - ks_assert(callbacks); - - if (callbacks->onshutdown) callbacks->onshutdown(value); - } - ks_hash_read_unlock(btmgr->transports); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_handle_t *) blade_transportmgr_handle_get(blade_transportmgr_t *btmgr) -{ - ks_assert(btmgr); - - return btmgr->handle; -} - -KS_DECLARE(blade_transport_t *) blade_transportmgr_default_get(blade_transportmgr_t *btmgr) -{ - ks_assert(btmgr); - - return btmgr->default_transport; -} - -KS_DECLARE(ks_status_t) blade_transportmgr_default_set(blade_transportmgr_t *btmgr, blade_transport_t *bt) -{ - ks_assert(btmgr); - ks_assert(bt); - - btmgr->default_transport = bt; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(blade_transport_t *) blade_transportmgr_transport_lookup(blade_transportmgr_t *btmgr, const char *name, ks_bool_t ordefault) -{ - blade_transport_t *bt = NULL; - - ks_assert(btmgr); - - ks_hash_read_lock(btmgr->transports); - if (name && name[0]) bt = (blade_transport_t *)ks_hash_search(btmgr->transports, (void *)name, KS_UNLOCKED); - if (!bt && ordefault) bt = btmgr->default_transport; - // @todo if (bt) blade_transport_read_lock(bt); - ks_hash_read_unlock(btmgr->transports); - - return bt; - -} - -KS_DECLARE(ks_status_t) blade_transportmgr_transport_add(blade_transportmgr_t *btmgr, blade_transport_t *bt) -{ - char *key = NULL; - - ks_assert(btmgr); - ks_assert(bt); - - key = ks_pstrdup(ks_pool_get(btmgr), blade_transport_name_get(bt)); - ks_hash_insert(btmgr->transports, (void *)key, (void *)bt); - - ks_log(KS_LOG_DEBUG, "Transport Added: %s\n", key); - - return KS_STATUS_SUCCESS; - -} - -KS_DECLARE(ks_status_t) blade_transportmgr_transport_remove(blade_transportmgr_t *btmgr, blade_transport_t *bt) -{ - const char *name = NULL; - - ks_assert(btmgr); - ks_assert(bt); - - name = blade_transport_name_get(bt); - ks_hash_remove(btmgr->transports, (void *)name); - - ks_log(KS_LOG_DEBUG, "Transport Removed: %s\n", name); - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_tuple.c b/libs/libblade/src/blade_tuple.c deleted file mode 100644 index 22fec25a42..0000000000 --- a/libs/libblade/src/blade_tuple.c +++ /dev/null @@ -1,107 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_tuple_s { - void *value1; - void *value2; -}; - - -static void blade_tuple_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //blade_tuple_t *bt = (blade_tuple_t *)ptr; - - //ks_assert(bt); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_tuple_create(blade_tuple_t **btP, ks_pool_t *pool, void *value1, void *value2) -{ - blade_tuple_t *bt = NULL; - - ks_assert(btP); - ks_assert(pool); - - bt = ks_pool_alloc(pool, sizeof(blade_tuple_t)); - bt->value1 = value1; - bt->value2 = value2; - - ks_pool_set_cleanup(bt, NULL, blade_tuple_cleanup); - - *btP = bt; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_tuple_destroy(blade_tuple_t **btP) -{ - ks_assert(btP); - ks_assert(*btP); - - ks_pool_free(btP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(void *) blade_tuple_value1_get(blade_tuple_t *bt) -{ - ks_assert(bt); - return bt->value1; -} - -KS_DECLARE(void *) blade_tuple_value2_get(blade_tuple_t *bt) -{ - ks_assert(bt); - return bt->value2; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/blade_web.c b/libs/libblade/src/blade_web.c deleted file mode 100644 index 526726a7b1..0000000000 --- a/libs/libblade/src/blade_web.c +++ /dev/null @@ -1,674 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "blade.h" - -struct blade_webrequest_s { - const char *action; - const char *path; - - ks_hash_t *query; - ks_hash_t *headers; - - ks_sb_t *content; -}; - -struct blade_webresponse_s { - const char *status_code; - const char *status_message; - - ks_hash_t *headers; - - ks_sb_t *content; -}; - -static void blade_webrequest_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_webrequest_t *bwreq = (blade_webrequest_t *)ptr; - - ks_assert(bwreq); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -static void blade_webresponse_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - blade_webresponse_t *bwres = (blade_webresponse_t *)ptr; - - ks_assert(bwres); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -KS_DECLARE(ks_status_t) blade_webrequest_create(blade_webrequest_t **bwreqP, const char *action, const char *path) -{ - ks_pool_t *pool = NULL; - blade_webrequest_t *bwreq = NULL; - - ks_assert(bwreqP); - ks_assert(action); - ks_assert(path); - - ks_pool_open(&pool); - ks_assert(pool); - - bwreq = ks_pool_alloc(pool, sizeof(blade_webrequest_t)); - - bwreq->action = ks_pstrdup(pool, action); - bwreq->path = ks_pstrdup(pool, path); - - ks_hash_create(&bwreq->query, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bwreq->query); - - ks_hash_create(&bwreq->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bwreq->headers); - - ks_sb_create(&bwreq->content, pool, 0); - ks_assert(bwreq->content); - - ks_pool_set_cleanup(bwreq, NULL, blade_webrequest_cleanup); - - *bwreqP = bwreq; - - blade_webrequest_header_add(bwreq, "Content-Type", "application/x-www-form-urlencoded"); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webrequest_load(blade_webrequest_t **bwreqP, struct mg_connection *conn) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_t *pool = NULL; - blade_webrequest_t *bwreq = NULL; - const struct mg_request_info *info = NULL; - char buf[1024]; - int bytes = 0; - - ks_assert(bwreqP); - ks_assert(conn); - - info = mg_get_request_info(conn); - - ks_pool_open(&pool); - ks_assert(pool); - - bwreq = ks_pool_alloc(pool, sizeof(blade_webrequest_t)); - - bwreq->action = ks_pstrdup(pool, info->request_method); - bwreq->path = ks_pstrdup(pool, info->request_uri); - - ks_hash_create(&bwreq->query, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bwreq->query); - - ks_hash_create(&bwreq->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bwreq->headers); - - ks_sb_create(&bwreq->content, pool, 0); - ks_assert(bwreq->content); - - ks_pool_set_cleanup(bwreq, NULL, blade_webrequest_cleanup); - - if (info->query_string && info->query_string[0]) { - char *query = ks_pstrdup(pool, info->query_string); - char *start = query; - char *end = NULL; - - do { - char *key = start; - char *value = NULL; - - end = strchr(start, '&'); - if (end) *end = '\0'; - - value = strchr(start, '='); - if (value) { - *value = '\0'; - value++; - - if (*key && *value) { - ks_hash_insert(bwreq->query, (void *)ks_pstrdup(pool, key), (void *)ks_pstrdup(pool, value)); - } - } - - if (end) start = ++end; - else start = NULL; - } while (start); - - ks_pool_free(&query); - } - - for (int index = 0; index < info->num_headers; ++index) { - const struct mg_header *header = &info->http_headers[index]; - ks_hash_insert(bwreq->headers, (void *)ks_pstrdup(pool, header->name), (void *)ks_pstrdup(pool, header->value)); - } - - while ((bytes = mg_read(conn, buf, sizeof(buf))) > 0) ks_sb_append_ex(bwreq->content, buf, bytes); - if (bytes < 0) { - blade_webrequest_destroy(&bwreq); - ret = KS_STATUS_FAIL; - } - else *bwreqP = bwreq; - - return ret; -} - -KS_DECLARE(ks_status_t) blade_webrequest_destroy(blade_webrequest_t **bwreqP) -{ - blade_webrequest_t *bwreq = NULL; - ks_pool_t *pool; - - ks_assert(bwreqP); - ks_assert(*bwreqP); - - bwreq = *bwreqP; - *bwreqP = NULL; - - pool = ks_pool_get(bwreq); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_webrequest_action_get(blade_webrequest_t *bwreq) -{ - ks_assert(bwreq); - return bwreq->action; -} - -KS_DECLARE(const char *) blade_webrequest_path_get(blade_webrequest_t *bwreq) -{ - ks_assert(bwreq); - return bwreq->path; -} - -KS_DECLARE(ks_status_t) blade_webrequest_query_add(blade_webrequest_t *bwreq, const char *name, const char *value) -{ - ks_assert(bwreq); - ks_assert(name); - ks_assert(value); - - ks_hash_insert(bwreq->query, (void *)ks_pstrdup(ks_pool_get(bwreq), name), (void *)ks_pstrdup(ks_pool_get(bwreq), value)); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_webrequest_query_get(blade_webrequest_t *bwreq, const char *name) -{ - ks_assert(bwreq); - ks_assert(name); - - return (const char *)ks_hash_search(bwreq->query, (void *)name, KS_UNLOCKED); -} - -KS_DECLARE(ks_status_t) blade_webrequest_header_add(blade_webrequest_t *bwreq, const char *header, const char *value) -{ - ks_assert(bwreq); - ks_assert(header); - ks_assert(value); - - ks_hash_insert(bwreq->headers, (void *)ks_pstrdup(ks_pool_get(bwreq), header), (void *)ks_pstrdup(ks_pool_get(bwreq), value)); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webrequest_header_printf(blade_webrequest_t *bwreq, const char *header, const char *fmt, ...) -{ - va_list ap; - char *result = NULL; - - ks_assert(bwreq); - ks_assert(header); - ks_assert(fmt); - - va_start(ap, fmt); - result = ks_vpprintf(ks_pool_get(bwreq), fmt, ap); - va_end(ap); - - ks_hash_insert(bwreq->headers, (void *)ks_pstrdup(ks_pool_get(bwreq), header), (void *)result); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_webrequest_header_get(blade_webrequest_t *bwreq, const char *header) -{ - ks_assert(bwreq); - ks_assert(header); - - return (const char *)ks_hash_search(bwreq->headers, (void *)header, KS_UNLOCKED); -} - -KS_DECLARE(ks_status_t) blade_webrequest_content_json_append(blade_webrequest_t *bwreq, cJSON *json) -{ - ks_assert(bwreq); - ks_assert(json); - - blade_webrequest_header_add(bwreq, "Content-Type", "application/json"); - - ks_sb_json(bwreq->content, json); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webrequest_content_string_append(blade_webrequest_t *bwreq, const char *str) -{ - ks_assert(bwreq); - ks_assert(str); - - ks_sb_append(bwreq->content, str); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webrequest_send(blade_webrequest_t *bwreq, ks_bool_t secure, const char *host, ks_port_t port, blade_webresponse_t **bwresP) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - char buf[1024]; - struct mg_connection *conn = NULL; - const char *path = NULL; - ks_sb_t *pathAndQuery = NULL; - - ks_assert(bwreq); - ks_assert(host); - ks_assert(bwresP); - - if (port == 0) port = secure ? 443 : 80; - - conn = mg_connect_client(host, port, secure, buf, sizeof(buf)); - if (!conn) { - ret = KS_STATUS_FAIL; - goto done; - } - - path = bwreq->path; - if (ks_hash_count(bwreq->query) > 0) { - ks_bool_t firstQuery = KS_TRUE; - - ks_sb_create(&pathAndQuery, NULL, 0); - ks_sb_append(pathAndQuery, bwreq->path); - for (ks_hash_iterator_t *it = ks_hash_first(bwreq->query, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key; - const char *value; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - - // @todo make sure key and value are URL encoded - mg_url_encode(key, buf, sizeof(buf)); - ks_sb_printf(pathAndQuery, "%c%s=", firstQuery ? '?' : '&', buf); - - mg_url_encode(value, buf, sizeof(buf)); - ks_sb_append(pathAndQuery, buf); - - firstQuery = KS_FALSE; - } - - path = ks_sb_cstr(pathAndQuery); - } - - mg_printf(conn, - "%s %s HTTP/1.1\r\n" - "Host: %s\r\n" - "Content-Length: %lu\r\n", - bwreq->action, - path, - host, - ks_sb_length(bwreq->content)); - - if (pathAndQuery) ks_sb_destroy(&pathAndQuery); - - for (ks_hash_iterator_t *it = ks_hash_first(bwreq->headers, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key; - const char *value; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - mg_printf(conn, "%s: %s\r\n", key, value); - } - - mg_write(conn, "\r\n", 2); - - mg_write(conn, ks_sb_cstr(bwreq->content), ks_sb_length(bwreq->content)); - - if (mg_get_response(conn, buf, sizeof(buf), 1000) <= 0) { - ret = KS_STATUS_FAIL; - goto done; - } - - ret = blade_webresponse_load(bwresP, conn); - -done: - if (conn) mg_close_connection(conn); - return ret; -} - -KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_credentials_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char **token) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_webrequest_t *bwreq = NULL; - blade_webresponse_t *bwres = NULL; - cJSON *json = NULL; - char *auth = NULL; - char encoded[1024]; - ks_pool_t *pool = NULL; - const char *tok = NULL; - - ks_assert(host); - ks_assert(path); - ks_assert(client_id); - ks_assert(client_secret); - ks_assert(token); - - blade_webrequest_create(&bwreq, "POST", path); - - auth = ks_psprintf(ks_pool_get(bwreq), "%s:%s", client_id, client_secret); - ks_b64_encode((unsigned char *)auth, strlen(auth), (unsigned char *)encoded, sizeof(encoded)); - ks_pool_free(&auth); - - blade_webrequest_header_printf(bwreq, "Authorization", "Basic %s", encoded); - - json = cJSON_CreateObject(); - cJSON_AddStringToObject(json, "grant_type", "client_credentials"); - blade_webrequest_content_json_append(bwreq, json); - cJSON_Delete(json); - - if ((ret = blade_webrequest_send(bwreq, secure, host, port, &bwres)) != KS_STATUS_SUCCESS) goto done; - - if ((ret = blade_webresponse_content_json_get(bwres, &json)) != KS_STATUS_SUCCESS) goto done; - - if ((tok = cJSON_GetObjectCstr(json, "access_token")) == NULL) { - ret = KS_STATUS_FAIL; - goto done; - } - - ks_pool_open(&pool); - *token = ks_pstrdup(pool, tok); - -done: - if (json) cJSON_Delete(json); - blade_webrequest_destroy(&bwreq); - if (bwres) blade_webresponse_destroy(&bwres); - - return ret; -} - -KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_code_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char *code, const char **token) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - blade_webrequest_t *bwreq = NULL; - blade_webresponse_t *bwres = NULL; - cJSON *json = NULL; - char *auth = NULL; - char encoded[1024]; - ks_pool_t *pool = NULL; - const char *tok = NULL; - - ks_assert(host); - ks_assert(path); - ks_assert(client_id); - ks_assert(client_secret); - ks_assert(code); - ks_assert(token); - - blade_webrequest_create(&bwreq, "POST", path); - - auth = ks_psprintf(ks_pool_get(bwreq), "%s:%s", client_id, client_secret); - ks_b64_encode((unsigned char *)auth, strlen(auth), (unsigned char *)encoded, sizeof(encoded)); - ks_pool_free(&auth); - - blade_webrequest_header_printf(bwreq, "Authorization", "Basic %s", encoded); - - json = cJSON_CreateObject(); - cJSON_AddStringToObject(json, "grant_type", "authorization_code"); - cJSON_AddStringToObject(json, "code", code); - blade_webrequest_content_json_append(bwreq, json); - cJSON_Delete(json); - - if ((ret = blade_webrequest_send(bwreq, secure, host, port, &bwres)) != KS_STATUS_SUCCESS) goto done; - - if ((ret = blade_webresponse_content_json_get(bwres, &json)) != KS_STATUS_SUCCESS) goto done; - - if ((tok = cJSON_GetObjectCstr(json, "access_token")) == NULL) { - ret = KS_STATUS_FAIL; - goto done; - } - - ks_pool_open(&pool); - *token = ks_pstrdup(pool, tok); - -done: - if (json) cJSON_Delete(json); - blade_webrequest_destroy(&bwreq); - if (bwres) blade_webresponse_destroy(&bwres); - - return ret; -} - - -KS_DECLARE(ks_status_t) blade_webresponse_create(blade_webresponse_t **bwresP, const char *status) -{ - ks_pool_t *pool = NULL; - blade_webresponse_t *bwres = NULL; - - ks_assert(bwresP); - ks_assert(status); - - ks_pool_open(&pool); - ks_assert(pool); - - bwres = ks_pool_alloc(pool, sizeof(blade_webresponse_t)); - - bwres->status_code = ks_pstrdup(pool, status); - bwres->status_message = ks_pstrdup(pool, mg_get_response_code_text(NULL, atoi(status))); - - ks_hash_create(&bwres->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bwres->headers); - - ks_sb_create(&bwres->content, pool, 0); - ks_assert(bwres->content); - - ks_pool_set_cleanup(bwres, NULL, blade_webresponse_cleanup); - - *bwresP = bwres; - - blade_webresponse_header_add(bwres, "Content-Type", "application/x-www-form-urlencoded"); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webresponse_load(blade_webresponse_t **bwresP, struct mg_connection *conn) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_t *pool = NULL; - blade_webresponse_t *bwres = NULL; - const struct mg_request_info *info = NULL; - char buf[1024]; - int bytes = 0; - - ks_assert(bwresP); - ks_assert(conn); - - info = mg_get_request_info(conn); - - ks_pool_open(&pool); - ks_assert(pool); - - bwres = ks_pool_alloc(pool, sizeof(blade_webrequest_t)); - - bwres->status_code = ks_pstrdup(pool, info->request_uri); - bwres->status_message = ks_pstrdup(pool, info->http_version); - - ks_hash_create(&bwres->headers, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE, pool); - ks_assert(bwres->headers); - - ks_sb_create(&bwres->content, pool, 0); - ks_assert(bwres->content); - - ks_pool_set_cleanup(bwres, NULL, blade_webresponse_cleanup); - - for (int index = 0; index < info->num_headers; ++index) { - const struct mg_header *header = &info->http_headers[index]; - ks_hash_insert(bwres->headers, (void *)ks_pstrdup(pool, header->name), (void *)ks_pstrdup(pool, header->value)); - } - - while ((bytes = mg_read(conn, buf, sizeof(buf))) > 0) ks_sb_append_ex(bwres->content, buf, bytes); - if (bytes < 0) { - blade_webresponse_destroy(&bwres); - ret = KS_STATUS_FAIL; - } - else *bwresP = bwres; - - return ret; -} - -KS_DECLARE(ks_status_t) blade_webresponse_destroy(blade_webresponse_t **bwresP) -{ - blade_webresponse_t *bwres = NULL; - ks_pool_t *pool; - - ks_assert(bwresP); - ks_assert(*bwresP); - - bwres = *bwresP; - *bwresP = NULL; - - pool = ks_pool_get(bwres); - - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webresponse_header_add(blade_webresponse_t *bwres, const char *header, const char *value) -{ - ks_assert(bwres); - ks_assert(header); - ks_assert(value); - - ks_hash_insert(bwres->headers, (void *)ks_pstrdup(ks_pool_get(bwres), header), (void *)ks_pstrdup(ks_pool_get(bwres), value)); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) blade_webresponse_header_get(blade_webresponse_t *bwres, const char *header) -{ - ks_assert(bwres); - ks_assert(header); - - return (const char *)ks_hash_search(bwres->headers, (void *)header, KS_UNLOCKED); -} - -KS_DECLARE(ks_status_t) blade_webresponse_content_json_append(blade_webresponse_t *bwres, cJSON *json) -{ - ks_assert(bwres); - ks_assert(json); - - blade_webresponse_header_add(bwres, "Content-Type", "application/json"); - - ks_sb_json(bwres->content, json); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webresponse_content_string_append(blade_webresponse_t *bwres, const char *str) -{ - ks_assert(bwres); - ks_assert(str); - - ks_sb_append(bwres->content, str); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) blade_webresponse_content_json_get(blade_webresponse_t *bwres, cJSON **json) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(bwres); - ks_assert(json); - - if (!(*json = cJSON_Parse(ks_sb_cstr(bwres->content)))) ret = KS_STATUS_FAIL; - - return ret; -} - -KS_DECLARE(ks_status_t) blade_webresponse_send(blade_webresponse_t *bwres, struct mg_connection *conn) -{ - ks_assert(bwres); - ks_assert(conn); - - mg_printf(conn, - "HTTP/1.1 %s %s\r\n" - "Content-Length: %lu\r\n" - "Connection: close\r\n", - bwres->status_code, - bwres->status_message, - ks_sb_length(bwres->content)); - - for (ks_hash_iterator_t *it = ks_hash_first(bwres->headers, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const char *key; - const char *value; - - ks_hash_this(it, (const void **)&key, NULL, (void **)&value); - mg_printf(conn, "%s: %s\r\n", key, value); - } - - mg_write(conn, "\r\n", 2); - - mg_write(conn, ks_sb_cstr(bwres->content), ks_sb_length(bwres->content)); - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht.c b/libs/libblade/src/dht/ks_dht.c deleted file mode 100644 index 9e9c530d12..0000000000 --- a/libs/libblade/src/dht/ks_dht.c +++ /dev/null @@ -1,3278 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" -#include "sodium.h" - -void ks_dht_endpoint_destructor(void *ptr) { ks_dht_endpoint_destroy((ks_dht_endpoint_t **)&ptr); } - -void ks_dht_transaction_destructor(void *ptr) { ks_dht_transaction_destroy((ks_dht_transaction_t **)&ptr); } - -void ks_dht_storageitem_destructor(void *ptr) { ks_dht_storageitem_destroy((ks_dht_storageitem_t **)&ptr); } - -KS_DECLARE(ks_status_t) ks_dht_create(ks_dht_t **dht, ks_pool_t *pool, ks_thread_pool_t *tpool, ks_dht_nodeid_t *nodeid) -{ - ks_bool_t pool_alloc = !pool; - ks_dht_t *d = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(nodeid); - - *dht = NULL; - - /** - * Create a new internally managed pool if one wasn't provided, and returns KS_STATUS_NO_MEM if pool was not created. - */ - if (pool_alloc) { - ks_pool_open(&pool); - ks_assert(pool); - } - - /** - * Allocate the dht instance from the pool, and returns KS_STATUS_NO_MEM if the dht was not created. - */ - *dht = d = ks_pool_alloc(pool, sizeof(ks_dht_t)); - ks_assert(d); - - /** - * Keep track of the pool used for future allocations and cleanup. - * Keep track of whether the pool was created internally or not. - */ - d->pool = pool; - d->pool_alloc = pool_alloc; - - /** - * Create a new internally managed thread pool if one wasn't provided. - */ - d->tpool = tpool; - if (!tpool) { - d->tpool_alloc = KS_TRUE; - ks_thread_pool_create(&d->tpool, KS_DHT_TPOOL_MIN, KS_DHT_TPOOL_MAX, KS_DHT_TPOOL_STACK, KS_PRI_NORMAL, KS_DHT_TPOOL_IDLE); - ks_assert(d->tpool); - } - - d->nodeid = *nodeid; - - /** - * Default autorouting to disabled. - */ - d->autoroute = KS_FALSE; - d->autoroute_port = 0; - - /** - * Create the message type registry. - */ - ks_hash_create(&d->registry_type, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, d->pool); - ks_assert(d->registry_type); - - /** - * Register the message type callbacks for query (q), response (r), and error (e) - */ - ks_dht_register_type(d, "q", ks_dht_process_query); - ks_dht_register_type(d, "r", ks_dht_process_response); - ks_dht_register_type(d, "e", ks_dht_process_error); - - /** - * Create the message query registry. - */ - ks_hash_create(&d->registry_query, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, d->pool); - ks_assert(d->registry_query); - - /** - * Register the message query callbacks for ping, find_node, etc. - */ - ks_dht_register_query(d, "ping", ks_dht_process_query_ping); - ks_dht_register_query(d, "find_node", ks_dht_process_query_findnode); - ks_dht_register_query(d, "get", ks_dht_process_query_get); - ks_dht_register_query(d, "put", ks_dht_process_query_put); - - /** - * Create the message error registry. - */ - ks_hash_create(&d->registry_error, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, d->pool); - ks_assert(d->registry_error); - // @todo register 301 error for internal get/put CAS hash mismatch retry handler - - /** - * Initialize the data used to track endpoints to NULL, binding will handle latent allocations. - * The endpoints and endpoints_poll arrays are maintained in parallel to optimize polling. - */ - d->endpoints = NULL; - d->endpoints_length = 0; - d->endpoints_size = 0; - d->endpoints_poll = NULL; - - /** - * Create the endpoints hash for fast lookup, this is used to route externally provided remote addresses when the local endpoint is unknown. - * This also provides the basis for autorouting to find unbound interfaces and bind them at runtime. - * This hash uses the host ip string concatenated with a colon and the port, ie: "123.123.123.123:123" or ipv6 equivilent - */ - ks_hash_create_ex(&d->endpoints_hash, - 2, - NULL, - NULL, - KS_HASH_MODE_CASE_INSENSITIVE, - KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, - ks_dht_endpoint_destructor, - d->pool); - ks_assert(d->endpoints_hash); - - /** - * Default transactions expirations to not be checked for one pulse. - */ - d->transactions_pulse = ks_time_now() + ((ks_time_t)KS_DHT_TRANSACTIONS_PULSE * KS_USEC_PER_SEC); - - /** - * Create the queue for outgoing messages, this ensures sending remains async and can be throttled when system buffers are full. - */ - ks_q_create(&d->send_q, d->pool, 0); - ks_assert(d->send_q); - - /** - * If a message is popped from the queue for sending but the system buffers are too full, this is used to temporarily store the message. - */ - d->send_q_unsent = NULL; - - /** - * The dht uses a single internal large receive buffer for receiving all frames, this may change in the future to offload processing to a threadpool. - */ - d->recv_buffer_length = 0; - - /** - * Initialize the jobs mutex - */ - ks_mutex_create(&d->jobs_mutex, KS_MUTEX_FLAG_DEFAULT, d->pool); - ks_assert(d->jobs_mutex); - - d->jobs_first = NULL; - d->jobs_last = NULL; - - /** - * Initialize the transaction id mutex, should use atomic increment instead - */ - ks_mutex_create(&d->transactionid_mutex, KS_MUTEX_FLAG_DEFAULT, d->pool); - ks_assert(d->transactionid_mutex); - - /** - * Initialize the first transaction id randomly, this doesn't really matter. - */ - d->transactionid_next = 1; //rand(); - - /** - * Create the hash to track pending transactions on queries that are pending responses. - * It should be impossible to receive a duplicate transaction id in the hash before it expires, but if it does an error is preferred. - */ - ks_hash_create_ex(&d->transactions_hash, - 16, - NULL, - NULL, - KS_HASH_MODE_INT, - KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, - ks_dht_transaction_destructor, - d->pool); - ks_assert(d->transactions_hash); - - /** - * The internal route tables will be latent allocated when binding. - */ - d->rt_ipv4 = NULL; - d->rt_ipv6 = NULL; - - /** - * Default tokens expirations to not be checked for one pulse. - */ - d->tokens_pulse = ks_time_now() + ((ks_time_t)KS_DHT_TOKENS_PULSE * KS_USEC_PER_SEC); - - /** - * The opaque write tokens require some entropy for generating which needs to change periodically but accept tokens using the last two secrets. - */ - d->token_secret_current = d->token_secret_previous = rand(); - d->token_secret_expiration = ks_time_now() + ((ks_time_t)KS_DHT_TOKEN_EXPIRATION * KS_USEC_PER_SEC); - - /** - * Default storageitems expirations to not be checked for one pulse. - */ - d->storageitems_pulse = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEMS_PULSE * KS_USEC_PER_SEC); - - /** - * Create the hash to store arbitrary data for BEP44. - */ - ks_hash_create_ex(&d->storageitems_hash, - 16, - NULL, - NULL, - KS_HASH_MODE_ARBITRARY, - KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, - ks_dht_storageitem_destructor, - d->pool); - ks_assert(d->storageitems_hash); - - /** - * The storageitems hash uses arbitrary key size, which requires the key size be provided, they are the same size as nodeid's. - */ - ks_hash_set_keysize(d->storageitems_hash, KS_DHT_NODEID_SIZE); - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (d) ks_dht_destroy(&d); - else if (pool_alloc && pool) ks_pool_close(&pool); - - *dht = NULL; - } - return ret; -} - -KS_DECLARE(void) ks_dht_destroy(ks_dht_t **dht) -{ - ks_dht_t *d = NULL; - ks_pool_t *pool = NULL; - ks_bool_t pool_alloc = KS_FALSE; - - ks_assert(dht); - ks_assert(*dht); - - d = *dht; - - // @todo ks_dht_shutdown to stop further incoming data and pulse to finish processing and flushing data - - /** - * Cleanup the type, query, and error registries if they have been allocated. - * No dependancies during destruction, entries are function pointers with no cleanup required. - */ - if (d->registry_type) ks_hash_destroy(&d->registry_type); - if (d->registry_query) ks_hash_destroy(&d->registry_query); - if (d->registry_error) ks_hash_destroy(&d->registry_error); - - /** - * Cleanup the endpoint management and entries if they have been allocated. - * No dependancies during destruction, entries are destroyed through hash destructor. - * Sockets are closed during entry destruction, and route table references to local nodes are released. - */ - if (d->endpoints) ks_pool_free(d->pool, &d->endpoints); - if (d->endpoints_poll) ks_pool_free(d->pool, &d->endpoints_poll); - if (d->endpoints_hash) ks_hash_destroy(&d->endpoints_hash); - - /** - * Cleanup the transaction management and entries if they have been allocated. - * No dependancies during destruction, entries are destroyed through hash destructor. - */ - if (d->transactionid_mutex) ks_mutex_destroy(&d->transactionid_mutex); - if (d->transactions_hash) ks_hash_destroy(&d->transactions_hash); - - /** - * Cleanup the message send queue and entries if they have been allocated. - * No dependancies during destruction, entries must be destroyed here. - */ - if (d->send_q) { - ks_dht_message_t *msg; - while (ks_q_pop_timeout(d->send_q, (void **)&msg, 1) == KS_STATUS_SUCCESS && msg) ks_dht_message_destroy(&msg); - ks_q_destroy(&d->send_q); - } - if (d->send_q_unsent) ks_dht_message_destroy(&d->send_q_unsent); - - /** - * Cleanup the jobs management and entries if they have been allocated. - * Route table node and storage item references are released, entries must be destroyed here. - */ - for (ks_dht_job_t *job = d->jobs_first, *jobn = NULL; job; job = jobn) { - jobn = job->next; - ks_dht_job_destroy(&job); - } - if (d->jobs_mutex) ks_mutex_destroy(&d->jobs_mutex); - - /** - * Cleanup the storageitems hash and it's contents if it is allocated. - * No dependancies during destruction, entries are destroyed through hash destructor. - */ - if (d->storageitems_hash) ks_hash_destroy(&d->storageitems_hash); - - /** - * Cleanup the route tables if they are allocated. - * No nodes should be referenced anymore by this point. - */ - if (d->rt_ipv4) ks_dhtrt_deinitroute(&d->rt_ipv4); - if (d->rt_ipv6) ks_dhtrt_deinitroute(&d->rt_ipv6); - - - /** - * If the thread pool was allocated internally, destroy it. - */ - if (d->tpool_alloc) ks_thread_pool_destroy(&d->tpool); - - - /** - * Temporarily store the allocator level variables because freeing the dht instance will invalidate it. - */ - pool = d->pool; - pool_alloc = d->pool_alloc; - - /** - * Free the dht instance from the pool, after this the dht instance memory is invalid. - */ - ks_pool_free(d->pool, dht); - d = NULL; - - /** - * If the pool was allocated internally, destroy it using the temporary variables stored earlier. - */ - if (pool_alloc) ks_pool_close(&pool); -} - - -KS_DECLARE(void) ks_dht_autoroute(ks_dht_t *dht, ks_bool_t autoroute, ks_port_t port) -{ - ks_assert(dht); - - /** - * If autorouting is being disabled, port is always set to zero, otherwise if the port is zero use the DHT default port - */ - if (!autoroute) port = 0; - else if (port <= 0) port = KS_DHT_DEFAULT_PORT; - - /** - * Set the autoroute state - */ - dht->autoroute = autoroute; - dht->autoroute_port = port; -} - -KS_DECLARE(ks_status_t) ks_dht_autoroute_check(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_endpoint_t **endpoint) -{ - // @todo lookup standard def for IPV6 max size - char ip[48 + 1]; - ks_dht_endpoint_t *ep = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(raddr); - ks_assert(endpoint); - - /** - * If the endpoint is already provided just leave it alone and return successfully. - */ - if (*endpoint) return KS_STATUS_SUCCESS; - - /** - * Use the remote address to figure out what local address we should use to attempt contacting it. - */ - if ((ret = ks_ip_route(ip, sizeof(ip), raddr->host)) != KS_STATUS_SUCCESS) return ret; - - /** - * Check if the endpoint has already been bound for the address we want to route through. - */ - ks_hash_read_lock(dht->endpoints_hash); - ep = ks_hash_search(dht->endpoints_hash, ip, KS_UNLOCKED); - ks_hash_read_unlock(dht->endpoints_hash); - - /** - * If the endpoint has not been bound, and autorouting is enabled then try to bind the new address. - */ - if (!ep && dht->autoroute) { - ks_sockaddr_t addr; - if ((ret = ks_addr_set(&addr, ip, dht->autoroute_port, raddr->family)) != KS_STATUS_SUCCESS) return ret; - if ((ret = ks_dht_bind(dht, &addr, &ep)) != KS_STATUS_SUCCESS) return ret; - } - - /** - * If no endpoint can be found to route through then all hope is lost, bail out with a failure. - */ - if (!ep) { - ks_log(KS_LOG_DEBUG, "No route available to %s\n", raddr->host); - return KS_STATUS_FAIL; - } - - /** - * Reaching here means an endpoint is available, assign it and return successfully. - */ - *endpoint = ep; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(void) ks_dht_register_type(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback) -{ - ks_assert(dht); - ks_assert(value); - ks_assert(callback); - - ks_hash_write_lock(dht->registry_type); - ks_hash_insert(dht->registry_type, (void *)value, (void *)(intptr_t)callback); - ks_hash_write_unlock(dht->registry_type); -} - -KS_DECLARE(void) ks_dht_register_query(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback) -{ - ks_assert(dht); - ks_assert(value); - ks_assert(callback); - - ks_hash_write_lock(dht->registry_query); - ks_hash_insert(dht->registry_query, (void *)value, (void *)(intptr_t)callback); - ks_hash_write_unlock(dht->registry_query); -} - -KS_DECLARE(void) ks_dht_register_error(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback) -{ - ks_assert(dht); - ks_assert(value); - ks_assert(callback); - - ks_hash_write_lock(dht->registry_error); - ks_hash_insert(dht->registry_error, (void *)value, (void *)(intptr_t)callback); - ks_hash_write_unlock(dht->registry_error); -} - - -KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint) -{ - ks_socket_t sock = KS_SOCK_INVALID; - ks_dht_endpoint_t *ep = NULL; - int32_t epindex = 0; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - ks_assert(addr->port); - - /** - * If capturing the endpoint output, make sure it is set NULL to start with. - */ - if (endpoint) *endpoint = NULL; - - ks_hash_write_lock(dht->endpoints_hash); - - if (ks_hash_search(dht->endpoints_hash, (void *)addr->host, KS_UNLOCKED)) { - ks_log(KS_LOG_DEBUG, "Attempted to bind to %s more than once.\n", addr->host); - ret = KS_STATUS_FAIL; - goto done; - } - - /** - * Attempt to open a UDP datagram socket for the given address family. - */ - if ((sock = socket(addr->family, SOCK_DGRAM, IPPROTO_UDP)) == KS_SOCK_INVALID) { - ret = KS_STATUS_FAIL; - goto done; - } - - /** - * Set some common socket options for non-blocking IO and forced binding when already in use - */ - if ((ret = ks_socket_option(sock, SO_REUSEADDR, KS_TRUE)) != KS_STATUS_SUCCESS) goto done; - if ((ret = ks_socket_option(sock, KS_SO_NONBLOCK, KS_TRUE)) != KS_STATUS_SUCCESS) goto done; - - /** - * Attempt to bind the socket to the desired local address. - */ - if ((ret = ks_addr_bind(sock, addr)) != KS_STATUS_SUCCESS) goto done; - - /** - * Allocate the endpoint to track the local socket. - */ - ks_dht_endpoint_create(&ep, dht->pool, addr, sock); - ks_assert(ep); - - /** - * Add the new endpoint into the endpoints hash for quick lookups. - */ - ks_hash_insert(dht->endpoints_hash, ep->addr.host, ep); - - /** - * Resize the endpoints array to take another endpoint pointer. - */ - epindex = dht->endpoints_length++; - if (dht->endpoints_length > dht->endpoints_size) { - dht->endpoints_size = dht->endpoints_length; - dht->endpoints = (ks_dht_endpoint_t **)ks_pool_resize(dht->pool, - (void *)dht->endpoints, - sizeof(ks_dht_endpoint_t *) * dht->endpoints_size); - ks_assert(dht->endpoints); - /** - * Resize the endpoints_poll array to keep in parallel with endpoints array. - */ - dht->endpoints_poll = (struct pollfd *)ks_pool_resize(dht->pool, - (void *)dht->endpoints_poll, - sizeof(struct pollfd) * dht->endpoints_size); - ks_assert(dht->endpoints_poll); - } - /** - * Populate the new endpoint data - */ - dht->endpoints[epindex] = ep; - dht->endpoints_poll[epindex].fd = ep->sock; - dht->endpoints_poll[epindex].events = POLLIN | POLLERR; - - - /** - * If the route table for the family doesn't exist yet, initialize a new route table and create a local node for the endpoint. - */ - if (ep->addr.family == AF_INET) { - if (!dht->rt_ipv4 && (ret = ks_dhtrt_initroute(&dht->rt_ipv4, dht, dht->pool)) != KS_STATUS_SUCCESS) goto done; - if ((ret = ks_dhtrt_create_node(dht->rt_ipv4, - dht->nodeid, - KS_DHT_LOCAL, - ep->addr.host, - ep->addr.port, - KS_DHTRT_CREATE_DEFAULT, - &dht->node)) != KS_STATUS_SUCCESS) goto done; - } else { - if (!dht->rt_ipv6 && (ret = ks_dhtrt_initroute(&dht->rt_ipv6, dht, dht->pool)) != KS_STATUS_SUCCESS) goto done; - if ((ret = ks_dhtrt_create_node(dht->rt_ipv6, - dht->nodeid, - KS_DHT_LOCAL, - ep->addr.host, - ep->addr.port, - KS_DHTRT_CREATE_DEFAULT, - &dht->node)) != KS_STATUS_SUCCESS) goto done; - } - /** - * Do not release the dht->node, keep it alive until cleanup - */ - - /** - * If the endpoint output is being captured, assign it and return successfully. - */ - if (endpoint) *endpoint = ep; - - done: - if (ret != KS_STATUS_SUCCESS) { - /** - * If any failures occur, we need to make sure the socket is properly closed. - * This will be done in ks_dht_endpoint_destroy only if the socket was assigned during a successful ks_dht_endpoint_create. - * Then return whatever failure condition resulted in landed here. - */ - if (ep) { - ks_hash_remove(dht->endpoints_hash, ep->addr.host); - dht->endpoints_length--; - } - else if (sock != KS_SOCK_INVALID) ks_socket_close(&sock); - - if (endpoint) *endpoint = NULL; - } - ks_hash_write_unlock(dht->endpoints_hash); - return ret; -} - -KS_DECLARE(void) ks_dht_pulse(ks_dht_t *dht, int32_t timeout) -{ - ks_assert(dht); - ks_assert(timeout >= 0 && timeout <= 1000); - // this should be called with a timeout of less than 1000ms, preferrably around 100ms - - ks_dht_pulse_endpoints(dht, timeout); - - if (dht->rt_ipv4) ks_dhtrt_process_table(dht->rt_ipv4); - if (dht->rt_ipv6) ks_dhtrt_process_table(dht->rt_ipv6); - - ks_dht_pulse_storageitems(dht); - - ks_dht_pulse_jobs(dht); - - ks_dht_pulse_send(dht); - - ks_dht_pulse_transactions(dht); - - ks_dht_pulse_tokens(dht); -} - -KS_DECLARE(void) ks_dht_pulse_endpoints(ks_dht_t *dht, int32_t timeout) -{ - ks_assert(dht); - ks_assert(timeout >= 0 && timeout <= 1000); - - if (dht->send_q_unsent || ks_q_size(dht->send_q) > 0) timeout = 0; - - if (ks_poll(dht->endpoints_poll, dht->endpoints_length, timeout) > 0) { - for (int32_t i = 0; i < dht->endpoints_length; ++i) { - ks_dht_datagram_t *datagram = NULL; - ks_sockaddr_t raddr = (const ks_sockaddr_t){ 0 }; - if (!(dht->endpoints_poll[i].revents & POLLIN)) continue; - - dht->recv_buffer_length = sizeof(dht->recv_buffer); - raddr.family = dht->endpoints[i]->addr.family; - if (ks_socket_recvfrom(dht->endpoints_poll[i].fd, dht->recv_buffer, &dht->recv_buffer_length, &raddr) != KS_STATUS_SUCCESS) continue; - - if (dht->recv_buffer_length == sizeof(dht->recv_buffer)) { - ks_log(KS_LOG_DEBUG, "Dropped oversize datagram from %s %d\n", raddr.host, raddr.port); - continue; - } - - ks_dht_datagram_create(&datagram, dht->pool, dht, dht->endpoints[i], &raddr); - ks_assert(datagram); - - if (ks_thread_pool_add_job(dht->tpool, ks_dht_process, datagram) != KS_STATUS_SUCCESS) ks_dht_datagram_destroy(&datagram); - } - } -} - -KS_DECLARE(void) ks_dht_pulse_storageitems(ks_dht_t *dht) -{ - ks_hash_iterator_t *it = NULL; - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_time_t now = ks_time_now(); - - ks_assert(dht); - - if (dht->storageitems_pulse > now) return; - dht->storageitems_pulse = now + ((ks_time_t)KS_DHT_STORAGEITEMS_PULSE * KS_USEC_PER_SEC); - - ks_hash_write_lock(dht->storageitems_hash); - for (it = ks_hash_first(dht->storageitems_hash, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const void *key = NULL; - ks_dht_storageitem_t *value = NULL; - ks_bool_t remove = KS_FALSE; - - ks_hash_this(it, &key, NULL, (void **)&value); - - ks_mutex_lock(value->mutex); - - if (value->keepalive <= now) { - value->keepalive = now + ((ks_time_t)KS_DHT_STORAGEITEM_KEEPALIVE * KS_USEC_PER_SEC); - if (value->refc > 0) { - value->expiration = now + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - ks_log(KS_LOG_DEBUG, "Item keepalive %s\n", ks_dht_hex(value->id.id, id_buf, KS_DHT_NODEID_SIZE)); - if (dht->rt_ipv4) ks_dht_distribute(dht, NULL, NULL, dht->rt_ipv4, 0, value); - if (dht->rt_ipv6) ks_dht_distribute(dht, NULL, NULL, dht->rt_ipv6, 0, value); - } - } - - remove = value->refc == 0 && value->expiration <= now; - if (remove) ks_hash_remove(dht->storageitems_hash, (void *)key); - - ks_mutex_unlock(value->mutex); - - if (remove) { - ks_log(KS_LOG_DEBUG, "Item expired %s\n", ks_dht_hex(value->id.id, id_buf, KS_DHT_NODEID_SIZE)); - ks_dht_storageitem_destroy(&value); - } - } - ks_hash_write_unlock(dht->storageitems_hash); -} - -KS_DECLARE(void) ks_dht_jobs_add(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_assert(dht); - ks_assert(job); - ks_mutex_lock(dht->jobs_mutex); - if (dht->jobs_last) dht->jobs_last = dht->jobs_last->next = job; - else dht->jobs_first = dht->jobs_last = job; - ks_mutex_unlock(dht->jobs_mutex); -} - -KS_DECLARE(void) ks_dht_pulse_jobs(ks_dht_t *dht) -{ - ks_dht_job_t *first = NULL; - ks_dht_job_t *last = NULL; - - ks_assert(dht); - - ks_mutex_lock(dht->jobs_mutex); - for (ks_dht_job_t *job = dht->jobs_first, *jobn = NULL, *jobp = NULL; job; job = jobn) { - jobn = job->next; - - if (job->state == KS_DHT_JOB_STATE_QUERYING) { - job->state = KS_DHT_JOB_STATE_RESPONDING; - if (job->query_callback(dht, job) != KS_STATUS_SUCCESS) { - job->result = KS_DHT_JOB_RESULT_FAILURE; - job->state = KS_DHT_JOB_STATE_COMPLETING; - } - } - if (job->state == KS_DHT_JOB_STATE_EXPIRING) { - job->attempts--; - if (job->attempts > 0) job->state = KS_DHT_JOB_STATE_QUERYING; - else { - job->result = KS_DHT_JOB_RESULT_EXPIRED; - job->state = KS_DHT_JOB_STATE_COMPLETING; - } - } - if (job->state == KS_DHT_JOB_STATE_COMPLETING) { - if (!jobp && !jobn) dht->jobs_first = dht->jobs_last = NULL; - else if (!jobp) dht->jobs_first = jobn; - else if (!jobn) { - dht->jobs_last = jobp; - dht->jobs_last->next = NULL; - } - else jobp->next = jobn; - - job->next = NULL; - if (last) last = last->next = job; - else first = last = job; - } else jobp = job; - } - ks_mutex_unlock(dht->jobs_mutex); - - for (ks_dht_job_t *job = first, *jobn = NULL; job; job = jobn) { - jobn = job->next; - // this cannot occur inside of the main loop, may add new jobs invalidating list pointers - if (job->finish_callback) job->finish_callback(dht, job); - ks_dht_job_destroy(&job); - } -} - -KS_DECLARE(void) ks_dht_pulse_send(ks_dht_t *dht) -{ - ks_dht_message_t *message; - ks_bool_t bail = KS_FALSE; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - - while (!bail) { - message = NULL; - if (dht->send_q_unsent) { - message = dht->send_q_unsent; - dht->send_q_unsent = NULL; - } - if (!message) bail = ks_q_pop_timeout(dht->send_q, (void **)&message, 1) != KS_STATUS_SUCCESS || !message; - if (!bail) { - bail = (ret = ks_dht_send(dht, message)) != KS_STATUS_SUCCESS; - if (ret == KS_STATUS_BREAK) dht->send_q_unsent = message; - else ks_dht_message_destroy(&message); - } - } -} - -KS_DECLARE(void) ks_dht_pulse_transactions(ks_dht_t *dht) -{ - ks_hash_iterator_t *it = NULL; - ks_time_t now = ks_time_now(); - - ks_assert(dht); - - if (dht->transactions_pulse > now) return; - dht->transactions_pulse = now + ((ks_time_t)KS_DHT_TRANSACTIONS_PULSE * KS_USEC_PER_SEC); - - ks_hash_write_lock(dht->transactions_hash); - for (it = ks_hash_first(dht->transactions_hash, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - const void *key = NULL; - ks_dht_transaction_t *value = NULL; - ks_bool_t remove = KS_FALSE; - - ks_hash_this(it, &key, NULL, (void **)&value); - if (value->finished) remove = KS_TRUE; - else if (value->expiration <= now) { - // if the transaction expires, so does the attached job, but the job may try again with a new transaction - value->job->state = KS_DHT_JOB_STATE_EXPIRING; - ks_log(KS_LOG_DEBUG, "Transaction has expired without response %d\n", value->transactionid); - remove = KS_TRUE; - } - if (remove) ks_hash_remove(dht->transactions_hash, (void *)key); - } - ks_hash_write_unlock(dht->transactions_hash); -} - -KS_DECLARE(void) ks_dht_pulse_tokens(ks_dht_t *dht) -{ - ks_time_t now = ks_time_now(); - - ks_assert(dht); - - if (dht->tokens_pulse > now) return; - dht->tokens_pulse = now + ((ks_time_t)KS_DHT_TOKENS_PULSE * KS_USEC_PER_SEC); - - if (dht->token_secret_expiration && dht->token_secret_expiration <= now) { - dht->token_secret_expiration = now + ((ks_time_t)KS_DHT_TOKEN_EXPIRATION * KS_USEC_PER_SEC); - dht->token_secret_previous = dht->token_secret_current; - dht->token_secret_current = rand(); - } -} - -KS_DECLARE(char *) ks_dht_hex(const uint8_t *data, char *buffer, ks_size_t len) -{ - char *t = buffer; - - ks_assert(data); - ks_assert(buffer); - - memset(buffer, 0, len * 2 + 1); - - for (int i = 0; i < len; ++i, t += 2) sprintf(t, "%02X", data[i]); - - return buffer; -} - -KS_DECLARE(uint8_t *) ks_dht_dehex(uint8_t *data, const char *buffer, ks_size_t len) -{ - const char *t = buffer; - - ks_assert(data); - ks_assert(buffer); - ks_assert(!(len & 1)); - - for (int i = 0; i < len; ++i, t += 2) sscanf(t, "%2hhx", &data[i]); - - return data; -} - -KS_DECLARE(void) ks_dht_utility_nodeid_xor(ks_dht_nodeid_t *dest, ks_dht_nodeid_t *src1, ks_dht_nodeid_t *src2) -{ - ks_assert(dest); - ks_assert(src1); - ks_assert(src2); - - for (int32_t i = 0; i < KS_DHT_NODEID_SIZE; ++i) dest->id[i] = src1->id[i] ^ src2->id[i]; -} - -KS_DECLARE(ks_status_t) ks_dht_utility_compact_addressinfo(const ks_sockaddr_t *address, - uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size) -{ - ks_size_t addr_len; - const void *paddr = NULL; - uint16_t port = 0; - - ks_assert(address); - ks_assert(buffer); - ks_assert(buffer_length); - ks_assert(buffer_size); - ks_assert(address->family == AF_INET || address->family == AF_INET6); - - addr_len = address->family == AF_INET ? sizeof(uint32_t) : (sizeof(uint16_t) * 8); - - if (*buffer_length + addr_len + sizeof(uint16_t) > buffer_size) { - ks_log(KS_LOG_DEBUG, "Insufficient space remaining for compacting\n"); - return KS_STATUS_NO_MEM; - } - - if (address->family == AF_INET) { - paddr = &address->v.v4.sin_addr; // already network byte order - port = address->v.v4.sin_port; // already network byte order - } else { - paddr = &address->v.v6.sin6_addr; // already network byte order - port = address->v.v6.sin6_port; // already network byte order - } - memcpy(buffer + (*buffer_length), paddr, sizeof(uint32_t)); - *buffer_length += addr_len; - - memcpy(buffer + (*buffer_length), &port, sizeof(uint16_t)); - *buffer_length += sizeof(uint16_t); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_dht_utility_expand_addressinfo(const uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size, - ks_sockaddr_t *address) -{ - ks_size_t addr_len; - const void *paddr = NULL; - uint16_t port = 0; - - ks_assert(buffer); - ks_assert(buffer_length); - ks_assert(address); - ks_assert(address->family == AF_INET ||address->family == AF_INET6); - - addr_len = address->family == AF_INET ? sizeof(uint32_t) : (sizeof(uint16_t) * 8); - if (*buffer_length + addr_len + sizeof(uint16_t) > buffer_size) return KS_STATUS_NO_MEM; - - paddr = buffer + *buffer_length; - *buffer_length += addr_len; - port = *((uint16_t *)(buffer + *buffer_length)); - *buffer_length += sizeof(uint16_t); - - return ks_addr_set_raw(address, paddr, port, address->family); -} - -KS_DECLARE(ks_status_t) ks_dht_utility_compact_nodeinfo(const ks_dht_nodeid_t *nodeid, - const ks_sockaddr_t *address, - uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size) -{ - ks_assert(address); - ks_assert(buffer); - ks_assert(buffer_length); - ks_assert(buffer_size); - ks_assert(address->family == AF_INET || address->family == AF_INET6); - - if (*buffer_length + KS_DHT_NODEID_SIZE > buffer_size) { - ks_log(KS_LOG_DEBUG, "Insufficient space remaining for compacting\n"); - return KS_STATUS_NO_MEM; - } - - memcpy(buffer + (*buffer_length), nodeid->id, KS_DHT_NODEID_SIZE); - *buffer_length += KS_DHT_NODEID_SIZE; - - return ks_dht_utility_compact_addressinfo(address, buffer, buffer_length, buffer_size); -} - -KS_DECLARE(ks_status_t) ks_dht_utility_expand_nodeinfo(const uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size, - ks_dht_nodeid_t *nodeid, - ks_sockaddr_t *address) -{ - ks_assert(buffer); - ks_assert(buffer_length); - ks_assert(nodeid); - ks_assert(address); - ks_assert(address->family == AF_INET ||address->family == AF_INET6); - - if (*buffer_length + KS_DHT_NODEID_SIZE > buffer_size) return KS_STATUS_NO_MEM; - - memcpy(nodeid->id, buffer + *buffer_length, KS_DHT_NODEID_SIZE); - *buffer_length += KS_DHT_NODEID_SIZE; - - return ks_dht_utility_expand_addressinfo(buffer, buffer_length, buffer_size, address); -} - -KS_DECLARE(ks_status_t) ks_dht_utility_extract_nodeid(struct bencode *args, const char *key, ks_dht_nodeid_t **nodeid) -{ - struct bencode *id; - const char *idv; - ks_size_t idv_len; - - ks_assert(args); - ks_assert(key); - ks_assert(nodeid); - - *nodeid = NULL; - - id = ben_dict_get_by_str(args, key); - if (!id) { - ks_log(KS_LOG_DEBUG, "Message args missing key '%s'\n", key); - return KS_STATUS_ARG_INVALID; - } - - idv = ben_str_val(id); - idv_len = ben_str_len(id); - if (idv_len != KS_DHT_NODEID_SIZE) { - ks_log(KS_LOG_DEBUG, "Message args '%s' value has an unexpected size of %d\n", key, idv_len); - return KS_STATUS_ARG_INVALID; - } - - *nodeid = (ks_dht_nodeid_t *)idv; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_dht_utility_extract_token(struct bencode *args, const char *key, ks_dht_token_t **token) -{ - struct bencode *tok; - const char *tokv; - ks_size_t tokv_len; - - ks_assert(args); - ks_assert(key); - ks_assert(token); - - *token = NULL; - - tok = ben_dict_get_by_str(args, key); - if (!tok) { - ks_log(KS_LOG_DEBUG, "Message args missing key '%s'\n", key); - return KS_STATUS_ARG_INVALID; - } - - tokv = ben_str_val(tok); - tokv_len = ben_str_len(tok); - if (tokv_len != KS_DHT_TOKEN_SIZE) { - ks_log(KS_LOG_DEBUG, "Message args '%s' value has an unexpected size of %d\n", key, tokv_len); - return KS_STATUS_ARG_INVALID; - } - - *token = (ks_dht_token_t *)tokv; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_dht_utility_extract_storageitem_pkey(struct bencode *args, - ks_bool_t optional, - const char *key, - ks_dht_storageitem_pkey_t **pkey) -{ - struct bencode *k; - const char *kv; - ks_size_t kv_len; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(args); - ks_assert(key); - ks_assert(pkey); - - *pkey = NULL; - - k = ben_dict_get_by_str(args, key); - if (!k) { - if (!optional) { - ks_log(KS_LOG_DEBUG, "Message args missing key '%s'\n", key); - ret = KS_STATUS_ARG_INVALID; - } - goto done; - } - - kv = ben_str_val(k); - kv_len = ben_str_len(k); - if (kv_len != KS_DHT_STORAGEITEM_PKEY_SIZE) { - ks_log(KS_LOG_DEBUG, "Message args '%s' value has an unexpected size of %d\n", key, kv_len); - return KS_STATUS_ARG_INVALID; - } - - *pkey = (ks_dht_storageitem_pkey_t *)kv; - - done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_utility_extract_storageitem_signature(struct bencode *args, - ks_bool_t optional, - const char *key, - ks_dht_storageitem_signature_t **signature) -{ - struct bencode *sig; - const char *sigv; - ks_size_t sigv_len; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(args); - ks_assert(key); - ks_assert(signature); - - *signature = NULL; - - sig = ben_dict_get_by_str(args, key); - if (!sig) { - if (!optional) { - ks_log(KS_LOG_DEBUG, "Message args missing key '%s'\n", key); - ret = KS_STATUS_ARG_INVALID; - } - goto done; - } - - sigv = ben_str_val(sig); - sigv_len = ben_str_len(sig); - if (sigv_len != KS_DHT_STORAGEITEM_SIGNATURE_SIZE) { - ks_log(KS_LOG_DEBUG, "Message args '%s' value has an unexpected size of %d\n", key, sigv_len); - return KS_STATUS_ARG_INVALID; - } - - *signature = (ks_dht_storageitem_signature_t *)sigv; - - done: - return ret; -} - - -KS_DECLARE(ks_status_t) ks_dht_token_generate(uint32_t secret, const ks_sockaddr_t *raddr, ks_dht_nodeid_t *target, ks_dht_token_t *token) -{ - SHA_CTX sha; - uint16_t port = 0; - - ks_assert(raddr); - ks_assert(raddr->family == AF_INET || raddr->family == AF_INET6); - ks_assert(target); - ks_assert(token); - - secret = htonl(secret); - port = htons(raddr->port); - - if (!SHA1_Init(&sha) || - !SHA1_Update(&sha, &secret, sizeof(uint32_t)) || - !SHA1_Update(&sha, raddr->host, strlen(raddr->host)) || - !SHA1_Update(&sha, &port, sizeof(uint16_t)) || - !SHA1_Update(&sha, target->id, KS_DHT_NODEID_SIZE) || - !SHA1_Final(token->token, &sha)) return KS_STATUS_FAIL; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_bool_t) ks_dht_token_verify(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_nodeid_t *target, ks_dht_token_t *token) -{ - ks_dht_token_t tok; - - if (ks_dht_token_generate(dht->token_secret_current, raddr, target, &tok) != KS_STATUS_SUCCESS) return KS_FALSE; - - if (memcmp(tok.token, token->token, KS_DHT_TOKEN_SIZE) == 0) return KS_TRUE; - - if (ks_dht_token_generate(dht->token_secret_previous, raddr, target, &tok) != KS_STATUS_SUCCESS) return KS_FALSE; - - return memcmp(tok.token, token->token, KS_DHT_TOKEN_SIZE) == 0; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_immutable_internal(struct bencode *value, ks_dht_nodeid_t *target) -{ - SHA_CTX sha; - uint8_t *v = NULL; - size_t v_len; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(value); - ks_assert(target); - - v = ben_encode(&v_len, value); - if (!SHA1_Init(&sha) || - !SHA1_Update(&sha, v, v_len) || - !SHA1_Final(target->id, &sha)) { - ret = KS_STATUS_FAIL; - } - free(v); - - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_immutable(const uint8_t *value, ks_size_t value_length, ks_dht_nodeid_t *target) -{ - struct bencode *v = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(value); - ks_assert(value_length > 0); - ks_assert(target); - - v = ben_blob(value, value_length); - ret = ks_dht_storageitem_target_immutable_internal(v, target); - ben_free(v); - - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_mutable_internal(ks_dht_storageitem_pkey_t *pk, struct bencode *salt, ks_dht_nodeid_t *target) -{ - SHA_CTX sha; - //char buf1[KS_DHT_NODEID_SIZE * 2 + 1]; - - ks_assert(pk); - ks_assert(target); - - - if (!SHA1_Init(&sha) || - !SHA1_Update(&sha, pk->key, KS_DHT_STORAGEITEM_PKEY_SIZE)) return KS_STATUS_FAIL; - if (salt) { - const uint8_t *s = (const uint8_t *)ben_str_val(salt); - size_t s_len = ben_str_len(salt); - if (s_len > 0 && !SHA1_Update(&sha, s, s_len)) return KS_STATUS_FAIL; - } - if (!SHA1_Final(target->id, &sha)) return KS_STATUS_FAIL; - - //ks_log(KS_LOG_DEBUG, "Mutable ID: %s\n", ks_dht_hex(target->id, buf1, KS_DHT_NODEID_SIZE)); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_mutable(ks_dht_storageitem_pkey_t *pk, const uint8_t *salt, ks_size_t salt_length, ks_dht_nodeid_t *target) -{ - struct bencode *s = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(pk); - ks_assert(target); - - if (salt && salt_length > 0) s = ben_blob(salt, salt_length); - ret = ks_dht_storageitem_target_mutable_internal(pk, s, target); - if (s) ben_free(s); - - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_signature_encode(uint8_t **encoded, - ks_size_t *encoded_length, - struct bencode *salt, - struct bencode *seq, - struct bencode *v) -{ - char *enc = NULL; - char *salt_enc = NULL; - size_t salt_enc_length = 0; - char *seq_enc = NULL; - size_t seq_enc_length = 0; - char *v_enc = NULL; - size_t v_enc_length = 0; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(encoded); - ks_assert(encoded_length); - ks_assert(seq); - ks_assert(v); - - if (salt) salt_enc = ben_encode(&salt_enc_length, salt); - seq_enc = ben_encode(&seq_enc_length, seq); - v_enc = ben_encode(&v_enc_length, v); - - *encoded_length = (salt ? 6 : 0) + // 4:salt - salt_enc_length + - 5 + // 3:seq - seq_enc_length + - 3 + // 1:v - v_enc_length; - enc = malloc((*encoded_length) + 1); - *encoded = (uint8_t *)enc; - enc[0] = '\0'; - - if (salt) { - strncat(enc, "4:salt", 6); - strncat(enc, salt_enc, salt_enc_length); - } - strncat(enc, "3:seq", 5); - strncat(enc, seq_enc, seq_enc_length); - strncat(enc, "1:v", 3); - strncat(enc, v_enc, v_enc_length); - - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_signature_generate_internal(ks_dht_storageitem_signature_t *sig, - ks_dht_storageitem_skey_t *sk, - struct bencode *salt, - struct bencode *seq, - struct bencode *v) -{ - uint8_t *tmpsig = NULL; - size_t tmpsig_len = 0; - ks_status_t ret = KS_STATUS_SUCCESS; - //char buf1[KS_DHT_STORAGEITEM_SIGNATURE_SIZE * 2 + 1]; - - ks_assert(sig); - ks_assert(sk); - ks_assert(seq); - ks_assert(v); - - if ((ret = ks_dht_storageitem_signature_encode(&tmpsig, &tmpsig_len, salt, seq, v)) != KS_STATUS_SUCCESS) goto done; - - if (crypto_sign_detached(sig->sig, NULL, tmpsig, tmpsig_len, sk->key) != 0) { - ret = KS_STATUS_FAIL; - goto done; - } - //ks_log(KS_LOG_DEBUG, "Signed: %s\n", ks_dht_hex(sig->sig, buf1, KS_DHT_STORAGEITEM_SIGNATURE_SIZE)); - - done: - if (tmpsig) free(tmpsig); - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_signature_generate(ks_dht_storageitem_signature_t *sig, - ks_dht_storageitem_skey_t *sk, - const uint8_t *salt, - ks_size_t salt_length, - int64_t sequence, - const uint8_t *value, - ks_size_t value_length) -{ - struct bencode *s = NULL; - struct bencode *seq = NULL; - struct bencode *v = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(sig); - ks_assert(sk); - ks_assert(sequence > 0); - ks_assert(value); - ks_assert(value_length > 0); - - if (salt && salt_length > 0) s = ben_blob(salt, salt_length); - seq = ben_int(sequence); - v = ben_blob(value, value_length); - - ret = ks_dht_storageitem_signature_generate_internal(sig, sk, s, seq, v); - - if (s) ben_free(s); - ben_free(seq); - ben_free(v); - - return ret; -} - -KS_DECLARE(ks_bool_t) ks_dht_storageitem_signature_verify(ks_dht_storageitem_signature_t *sig, - ks_dht_storageitem_pkey_t *pk, - struct bencode *salt, - struct bencode *seq, - struct bencode *v) -{ - uint8_t *tmpsig = NULL; - size_t tmpsig_len = 0; - int32_t res = 0; - - ks_assert(sig); - ks_assert(pk); - ks_assert(seq); - ks_assert(v); - - if (ks_dht_storageitem_signature_encode(&tmpsig, &tmpsig_len, salt, seq, v) != KS_STATUS_SUCCESS) return KS_FALSE; - - res = crypto_sign_verify_detached(sig->sig, tmpsig, tmpsig_len, pk->key); - - if (tmpsig) free(tmpsig); - - return res == 0; -} - -KS_DECLARE(ks_status_t) ks_dht_send(ks_dht_t *dht, ks_dht_message_t *message) -{ - char buf[KS_DHT_DATAGRAM_BUFFER_SIZE + 1]; - ks_size_t buf_len; - - ks_assert(dht); - ks_assert(message); - ks_assert(message->endpoint); - ks_assert(message->data); - - // @todo blacklist check - - buf_len = ben_encode2(buf, sizeof(buf), message->data); - if (buf_len >= sizeof(buf)) { - ks_log(KS_LOG_DEBUG, "Dropping message that is too large\n"); - return KS_STATUS_FAIL; - } - - ks_log(KS_LOG_DEBUG, - "Sending message to %s %d on %s %d\n", - message->raddr.host, - message->raddr.port, - message->endpoint->addr.host, - message->endpoint->addr.port); - ks_log(KS_LOG_DEBUG, "%s\n", ben_print(message->data)); - - return ks_socket_sendto(message->endpoint->sock, (void *)buf, &buf_len, &message->raddr); -} - - -KS_DECLARE(ks_status_t) ks_dht_query_setup(ks_dht_t *dht, - ks_dht_job_t *job, - const char *query, - ks_dht_job_callback_t callback, - ks_dht_transaction_t **transaction, - ks_dht_message_t **message, - struct bencode **args) -{ - ks_dht_endpoint_t *ep = NULL; - uint32_t transactionid; - ks_dht_transaction_t *trans = NULL; - ks_dht_message_t *msg = NULL; - struct bencode *a = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - ks_assert(query); - ks_assert(callback); - ks_assert(message); - - if (transaction) *transaction = NULL; - *message = NULL; - - if ((ret = ks_dht_autoroute_check(dht, &job->raddr, &ep)) != KS_STATUS_SUCCESS) goto done; - - ks_mutex_lock(dht->transactionid_mutex); - transactionid = dht->transactionid_next++; - ks_mutex_unlock(dht->transactionid_mutex); - - ks_dht_transaction_create(&trans, dht->pool, job, transactionid, callback); - ks_assert(trans); - - ks_dht_message_create(&msg, dht->pool, ep, &job->raddr, KS_TRUE); - ks_assert(msg); - - // if ((ret = ks_dht_message_query(msg, transactionid, query, args)) != KS_STATUS_SUCCESS) goto done; - transactionid = htonl(transactionid); - - ben_dict_set(msg->data, ben_blob("t", 1), ben_blob((uint8_t *)&transactionid, sizeof(uint32_t))); - ben_dict_set(msg->data, ben_blob("y", 1), ben_blob("q", 1)); - ben_dict_set(msg->data, ben_blob("q", 1), ben_blob(query, strlen(query))); - - // @note a joins msg->data and will be freed with it - a = ben_dict(); - ks_assert(a); - ben_dict_set(msg->data, ben_blob("a", 1), a); - - if (args) *args = a; - - ben_dict_set(a, ben_blob("id", 2), ben_blob(dht->nodeid.id, KS_DHT_NODEID_SIZE)); - - *message = msg; - - ks_hash_write_lock(dht->transactions_hash); - ks_hash_insert(dht->transactions_hash, (void *)&trans->transactionid, trans); - ks_hash_write_unlock(dht->transactions_hash); - - if (transaction) *transaction = trans; - - done: - if (ret != KS_STATUS_SUCCESS) { - if (trans) ks_dht_transaction_destroy(&trans); - if (msg) ks_dht_message_destroy(&msg); - *message = NULL; - } - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_response_setup(ks_dht_t *dht, - ks_dht_endpoint_t *ep, - const ks_sockaddr_t *raddr, - uint8_t *transactionid, - ks_size_t transactionid_length, - ks_dht_message_t **message, - struct bencode **args) -{ - ks_dht_message_t *msg = NULL; - struct bencode *r = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(raddr); - ks_assert(transactionid); - ks_assert(message); - - *message = NULL; - - if (!ep && (ret = ks_dht_autoroute_check(dht, raddr, &ep)) != KS_STATUS_SUCCESS) goto done; - - ks_dht_message_create(&msg, dht->pool, ep, raddr, KS_TRUE); - ks_assert(msg); - - ben_dict_set(msg->data, ben_blob("t", 1), ben_blob(transactionid, transactionid_length)); - ben_dict_set(msg->data, ben_blob("y", 1), ben_blob("r", 1)); - - // @note r joins msg->data and will be freed with it - r = ben_dict(); - ks_assert(r); - ben_dict_set(msg->data, ben_blob("r", 1), r); - - if (args) *args = r; - - ben_dict_set(r, ben_blob("id", 2), ben_blob(dht->nodeid.id, KS_DHT_NODEID_SIZE)); - - *message = msg; - - done: - if (ret != KS_STATUS_SUCCESS) { - if (msg) ks_dht_message_destroy(&msg); - *message = NULL; - } - return ret; -} - - -KS_DECLARE(void *) ks_dht_process(ks_thread_t *thread, void *data) -{ - ks_dht_datagram_t *datagram = (ks_dht_datagram_t *)data; - ks_dht_message_t *message = NULL; - ks_dht_message_callback_t callback; - - ks_assert(thread); - ks_assert(data); - - ks_log(KS_LOG_DEBUG, - "Received message from %s %d on %s %d\n", - datagram->raddr.host, - datagram->raddr.port, - datagram->endpoint->addr.host, - datagram->endpoint->addr.port); - if (datagram->raddr.family != AF_INET && datagram->raddr.family != AF_INET6) { - ks_log(KS_LOG_DEBUG, "Message from unsupported address family\n"); - goto done; - } - - // @todo blacklist check for bad actor nodes - - ks_dht_message_create(&message, datagram->dht->pool, datagram->endpoint, &datagram->raddr, KS_FALSE); - ks_assert(message); - - if (ks_dht_message_parse(message, datagram->buffer, datagram->buffer_length) != KS_STATUS_SUCCESS) goto done; - - ks_hash_read_lock(datagram->dht->registry_type); - callback = (ks_dht_message_callback_t)(intptr_t)ks_hash_search(datagram->dht->registry_type, message->type, KS_UNLOCKED); - ks_hash_read_unlock(datagram->dht->registry_type); - - if (!callback) ks_log(KS_LOG_DEBUG, "Message type '%s' is not registered\n", message->type); - else callback(datagram->dht, message); - - done: - if (message) ks_dht_message_destroy(&message); - if (datagram) ks_dht_datagram_destroy(&datagram); - return NULL; -} - - -KS_DECLARE(ks_status_t) ks_dht_process_query(ks_dht_t *dht, ks_dht_message_t *message) -{ - struct bencode *q; - struct bencode *a; - const char *qv; - ks_size_t qv_len; - ks_dht_nodeid_t *id; - ks_dht_node_t *node; - char query[KS_DHT_MESSAGE_QUERY_MAX_SIZE]; - ks_dht_message_callback_t callback; - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(message); - - q = ben_dict_get_by_str(message->data, "q"); - if (!q) { - ks_log(KS_LOG_DEBUG, "Message query missing required key 'q'\n"); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query missing required key 'q'"); - ret = KS_STATUS_FAIL; - goto done; - } - - qv = ben_str_val(q); - qv_len = ben_str_len(q); - if (qv_len >= KS_DHT_MESSAGE_QUERY_MAX_SIZE) { - ks_log(KS_LOG_DEBUG, "Message query 'q' value has an unexpectedly large size of %d\n", qv_len); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query 'q' value is too large"); - ret = KS_STATUS_FAIL; - goto done; - } - - memcpy(query, qv, qv_len); - query[qv_len] = '\0'; - //ks_log(KS_LOG_DEBUG, "Message query is '%s'\n", query); - - a = ben_dict_get_by_str(message->data, "a"); - if (!a) { - ks_log(KS_LOG_DEBUG, "Message query missing required key 'a'\n"); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query missing required key 'a'"); - ret = KS_STATUS_FAIL; - goto done; - } - - message->args = a; - - if ((ret = ks_dht_utility_extract_nodeid(message->args, "id", &id)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query args missing required key 'id'"); - goto done; - } - message->args_id = *id; - - ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(id->id, id_buf, KS_DHT_NODEID_SIZE)); - if ((ret = ks_dhtrt_create_node(message->endpoint->addr.family == AF_INET ? dht->rt_ipv4 : dht->rt_ipv6, - *id, - KS_DHT_REMOTE, - message->raddr.host, - message->raddr.port, - KS_DHTRT_CREATE_PING, - &node)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal route table create node error"); - goto done; - } - if ((ret = ks_dhtrt_release_node(node)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal route table release node error"); - goto done; - } - - ks_hash_read_lock(dht->registry_query); - callback = (ks_dht_message_callback_t)(intptr_t)ks_hash_search(dht->registry_query, query, KS_UNLOCKED); - ks_hash_read_unlock(dht->registry_query); - - if (!callback) { - ks_log(KS_LOG_DEBUG, "Message query '%s' is not registered\n", query); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 204, - "Message query method is not registered"); - } - else ret = callback(dht, message); - - done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_response(ks_dht_t *dht, ks_dht_message_t *message) -{ - struct bencode *r; - ks_dht_nodeid_t *id; - ks_dht_node_t *node = NULL; - ks_dht_transaction_t *transaction; - uint32_t *tid; - uint32_t transactionid; - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(message); - - r = ben_dict_get_by_str(message->data, "r"); - if (!r) { - ks_log(KS_LOG_DEBUG, "Message response missing required key 'r'\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - message->args = r; - - if ((ret = ks_dht_utility_extract_nodeid(message->args, "id", &id)) != KS_STATUS_SUCCESS) goto done; - message->args_id = *id; - - ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(id->id, id_buf, KS_DHT_NODEID_SIZE)); - if ((ret = ks_dhtrt_create_node(message->endpoint->addr.family == AF_INET ? dht->rt_ipv4 : dht->rt_ipv6, - *id, - KS_DHT_REMOTE, - message->raddr.host, - message->raddr.port, - KS_DHTRT_CREATE_TOUCH, - &node)) != KS_STATUS_SUCCESS) goto done; - - ks_log(KS_LOG_DEBUG, "Touching node %s\n", ks_dht_hex(id->id, id_buf, KS_DHT_NODEID_SIZE)); - if ((ret = ks_dhtrt_touch_node(message->endpoint->addr.family == AF_INET ? dht->rt_ipv4 : dht->rt_ipv6, *id)) != KS_STATUS_SUCCESS) goto done; - - - tid = (uint32_t *)message->transactionid; - transactionid = ntohl(*tid); - - ks_log(KS_LOG_DEBUG, "Message response transaction id %d\n", transactionid); - - ks_hash_read_lock(dht->transactions_hash); - transaction = ks_hash_search(dht->transactions_hash, (void *)&transactionid, KS_UNLOCKED); - ks_hash_read_unlock(dht->transactions_hash); - - if (!transaction) ks_log(KS_LOG_DEBUG, "Message response rejected with unknown transaction id %d\n", transactionid); - else if (!ks_addr_cmp(&message->raddr, &transaction->job->raddr)) { - ks_log(KS_LOG_DEBUG, - "Message response rejected due to spoofing from %s %d, expected %s %d\n", - message->raddr.host, - message->raddr.port, - transaction->job->raddr.host, - transaction->job->raddr.port); - } else { - ks_dhtrt_sharelock_node(node); - transaction->job->response = message; - transaction->job->response_id = node; - message->transaction = transaction; - if ((ret = transaction->callback(dht, transaction->job)) != KS_STATUS_SUCCESS) transaction->job->result = KS_DHT_JOB_RESULT_FAILURE; - transaction->job->state = KS_DHT_JOB_STATE_COMPLETING; - - transaction->job->response = NULL; // message is destroyed after we return, stop using it - transaction->finished = KS_TRUE; - } - - done: - if (node) ks_dhtrt_release_node(node); - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_search_findnode_callback(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_search_t *search = NULL; - ks_dht_node_t **nodes = NULL; - ks_size_t nodes_count = 0; - ks_dht_nodeid_t distance; - int32_t results_index = -1; - ks_bool_t finished = KS_FALSE; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - ks_assert(job->data); - - search = (ks_dht_search_t *)job->data; - - ks_mutex_lock(search->mutex); - search->searching--; - - if (job->result != KS_DHT_JOB_RESULT_SUCCESS) { - finished = KS_TRUE; - goto done; - } - - ks_dht_utility_nodeid_xor(&distance, &job->response_id->nodeid, &search->target); - if (search->results_length < KS_DHT_SEARCH_RESULTS_MAX_SIZE) { - results_index = search->results_length; - search->results_length++; - } else { - for (int32_t index = 0; index < search->results_length; ++index) { - // Check if responding node is closer than the current result - if (memcmp(distance.id, search->distances[index].id, KS_DHT_NODEID_SIZE) < 0) { - // Only existing results which are further from the target than the responding node are considered for replacement - - // If this is the first node that is further then keep it and keep looking for existing results which are further than this result - // If additional results are further, and the current result is further than a previous result, use the current result as furthest to replace - if (results_index < 0) results_index = index; - else if (memcmp(search->distances[index].id, search->distances[results_index].id, KS_DHT_NODEID_SIZE) > 0) results_index = index; - } - } - } - - if (results_index >= 0) { - // The results are either not full yet, or this responding node is closer than the furthest existing result - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - char id2_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - char id3_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - - ks_log(KS_LOG_DEBUG, - "Set closer node id %s (%s) in search of target id %s at results index %d\n", - ks_dht_hex(job->response_id->nodeid.id, id_buf, KS_DHT_NODEID_SIZE), - ks_dht_hex(distance.id, id2_buf, KS_DHT_NODEID_SIZE), - ks_dht_hex(search->target.id, id3_buf, KS_DHT_NODEID_SIZE), - results_index); - - if (search->results[results_index]) ks_dhtrt_release_node(search->results[results_index]); - ks_dhtrt_sharelock_node(job->response_id); - - search->results[results_index] = job->response_id; - search->distances[results_index] = distance; - } - - nodes = job->raddr.family == AF_INET ? job->response_nodes : job->response_nodes6; - nodes_count = job->raddr.family == AF_INET ? job->response_nodes_count : job->response_nodes6_count; - - for (int32_t i = 0; i < nodes_count; ++i) { - ks_bool_t closer = KS_FALSE; - ks_dht_node_t *node = nodes[i]; - - // skip duplicates already searched - if (ks_hash_search(search->searched, node->nodeid.id, KS_UNLOCKED) != 0) continue; - - // calculate distance of new node from target - ks_dht_utility_nodeid_xor(&distance, &node->nodeid, &search->target); - - // if the results are not full, or the new node is closer than any result then the new node should be checked - if (search->results_length < KS_DHT_SEARCH_RESULTS_MAX_SIZE) closer = KS_TRUE; - for (int32_t index = 0; !closer && index < search->results_length; ++index) { - // Check if new node is closer than this current result - closer = memcmp(distance.id, search->distances[index].id, KS_DHT_NODEID_SIZE) < 0; - } - - if (closer) { - // track new node as searched and searching then send off a findnode query to validate it as a result and end up back here for new closer nodes - ks_hash_insert(search->searched, node->nodeid.id, (void *)KS_TRUE); - search->searching++; - - ks_dht_findnode(dht, &node->addr, ks_dht_search_findnode_callback, search, &search->target); - } - } - finished = search->searching == 0; - - done: - ks_mutex_unlock(search->mutex); - - if (finished) { - if (search->callback) search->callback(dht, job); - ks_dht_search_destroy(&search); - } - - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_query_search(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_search_t *search = NULL; - ks_dhtrt_querynodes_t query; - ks_bool_t finished = KS_FALSE; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - ks_assert(job->data); - - search = (ks_dht_search_t *)job->data; - - ks_mutex_lock(search->mutex); - - // find closest good nodes to target locally and store as the closest results - query.nodeid = search->target; - query.type = KS_DHT_REMOTE; - query.max = KS_DHT_SEARCH_RESULTS_MAX_SIZE; - query.family = search->table == dht->rt_ipv4 ? AF_INET : AF_INET6; - query.count = 0; - ks_dhtrt_findclosest_nodes(search->table, &query); - for (int32_t i = 0; i < query.count; ++i) { - ks_dht_node_t *node = query.nodes[i]; - - // skip duplicates already searched, this really shouldn't happen on a new search but we sanity check - if (ks_hash_search(search->searched, node->nodeid.id, KS_UNLOCKED) != 0) continue; - - ks_hash_insert(search->searched, node->nodeid.id, (void *)KS_TRUE); - search->searching++; - - ks_dht_findnode(dht, &node->addr, ks_dht_search_findnode_callback, search, &search->target); - } - ks_dhtrt_release_querynodes(&query); - finished = search->searching == 0; - - // done: - ks_mutex_unlock(search->mutex); - - if (finished) { - if (search->callback) search->callback(dht, job); - ks_dht_search_destroy(&search); - } - - return ret; -} - -KS_DECLARE(void) ks_dht_search(ks_dht_t *dht, - ks_dht_job_callback_t callback, - void *data, - ks_dhtrt_routetable_t *table, - ks_dht_nodeid_t *target) -{ - char target_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_dht_search_t *search = NULL; - ks_dht_job_t *job = NULL; - - ks_assert(dht); - ks_assert(table); - ks_assert(target); - - ks_log(KS_LOG_INFO, "[%s] Searching\n", ks_dht_hex(target->id, target_buf, KS_DHT_NODEID_SIZE)); - - ks_dht_search_create(&search, dht->pool, table, target, callback, data); - ks_assert(search); - - ks_dht_job_create(&job, dht->pool, NULL, 3, search); - ks_assert(job); - - ks_dht_job_build_search(job, ks_dht_query_search, NULL); - ks_dht_jobs_add(dht, job); -} - -KS_DECLARE(ks_status_t) ks_dht_publish_get_callback(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_publish_t *publish = NULL; - ks_bool_t finished = KS_FALSE; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - ks_assert(job->data); - - publish = (ks_dht_publish_t *)job->data; - - if (job->result != KS_DHT_JOB_RESULT_SUCCESS) { - finished = KS_TRUE; - goto done; - } - - if (!job->response_hasitem || (publish->item->mutable && job->response_seq < publish->item->seq)) { - ks_dht_put(dht, &job->raddr, publish->callback, publish->data, &job->response_token, publish->cas, publish->item); - } else finished = KS_TRUE; - - done: - if (finished) { - job->data = publish->data; - if (publish->callback) publish->callback(dht, job); - } - ks_dht_publish_destroy(&publish); - return ret; -} - -KS_DECLARE(void) ks_dht_publish(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - int64_t cas, - ks_dht_storageitem_t *item) -{ - char target_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_dht_publish_t *publish = NULL; - const uint8_t *salt = NULL; - size_t salt_length = 0; - - ks_assert(dht); - ks_assert(raddr); - ks_assert(cas >= 0); - ks_assert(item); - - ks_log(KS_LOG_INFO, "[%s] Publishing to %s %d\n", ks_dht_hex(item->id.id, target_buf, KS_DHT_NODEID_SIZE), raddr->host, raddr->port); - - if (item->salt) { - salt = (const uint8_t *)ben_str_val(item->salt); - salt_length = ben_str_len(item->salt); - } - - ks_dht_publish_create(&publish, dht->pool, callback, data, cas, item); - ks_assert(publish); - - ks_dht_get(dht, raddr, ks_dht_publish_get_callback, publish, &item->id, salt, salt_length); -} - -KS_DECLARE(ks_status_t) ks_dht_distribute_publish_callback(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_distribute_t *distribute = NULL; - ks_bool_t finished = KS_FALSE; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - ks_assert(job->data); - - distribute = (ks_dht_distribute_t *)job->data; - ks_mutex_lock(distribute->mutex); - distribute->publishing--; - finished = distribute->publishing == 0; - ks_mutex_unlock(distribute->mutex); - - if (finished) { - if (distribute->callback) distribute->callback(dht, distribute->item); - ks_dht_distribute_destroy(&distribute); - } - - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_distribute_search_callback(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_search_t *search = NULL; - ks_dht_distribute_t *distribute = NULL; - ks_bool_t finished = KS_FALSE; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - ks_assert(job->data); - - search = (ks_dht_search_t *)job->data; - ks_assert(search->data); - - distribute = (ks_dht_distribute_t *)search->data; - - ks_mutex_lock(distribute->mutex); - for (int32_t index = 0; index < search->results_length; ++index) { - ks_dht_node_t *node = search->results[index]; - if (node->type == KS_DHT_LOCAL) continue; - - distribute->publishing++; - ks_dht_publish(dht, &node->addr, ks_dht_distribute_publish_callback, distribute, distribute->cas, distribute->item); - } - finished = distribute->publishing == 0; - ks_mutex_unlock(distribute->mutex); - - if (finished) { - if (distribute->callback) distribute->callback(dht, distribute->item); - ks_dht_distribute_destroy(&distribute); - } - - return ret; -} - -KS_DECLARE(void) ks_dht_distribute(ks_dht_t *dht, - ks_dht_storageitem_callback_t callback, - void *data, - ks_dhtrt_routetable_t *table, - int64_t cas, - ks_dht_storageitem_t *item) -{ - char target_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_dht_distribute_t *distribute = NULL; - - ks_assert(dht); - ks_assert(table); - ks_assert(cas >= 0); - ks_assert(item); - - ks_log(KS_LOG_INFO, "[%s] Distributing\n", ks_dht_hex(item->id.id, target_buf, KS_DHT_NODEID_SIZE)); - - ks_dht_distribute_create(&distribute, dht->pool, callback, data, cas, item); - ks_assert(distribute); - - ks_dht_search(dht, ks_dht_distribute_search_callback, distribute, table, &item->id); -} - -KS_DECLARE(void) ks_dht_storageitems_read_lock(ks_dht_t *dht) -{ - ks_assert(dht); - ks_hash_read_lock(dht->storageitems_hash); -} - -KS_DECLARE(void) ks_dht_storageitems_read_unlock(ks_dht_t *dht) -{ - ks_assert(dht); - ks_hash_read_unlock(dht->storageitems_hash); -} - -KS_DECLARE(void) ks_dht_storageitems_write_lock(ks_dht_t *dht) -{ - ks_assert(dht); - ks_hash_write_lock(dht->storageitems_hash); -} - -KS_DECLARE(void) ks_dht_storageitems_write_unlock(ks_dht_t *dht) -{ - ks_assert(dht); - ks_hash_write_lock(dht->storageitems_hash); -} - -KS_DECLARE(ks_dht_storageitem_t *) ks_dht_storageitems_find(ks_dht_t *dht, ks_dht_nodeid_t *target) -{ - ks_dht_storageitem_t *item = NULL; - - ks_assert(dht); - ks_assert(target); - - item = ks_hash_search(dht->storageitems_hash, target->id, KS_UNLOCKED); - if (item) ks_dht_storageitem_reference(item); - - return item; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitems_insert(ks_dht_t *dht, ks_dht_storageitem_t *item) -{ - ks_assert(dht); - ks_assert(item); - - return ks_hash_insert(dht->storageitems_hash, item->id.id, item); -} - - -KS_DECLARE(ks_status_t) ks_dht_error(ks_dht_t *dht, - ks_dht_endpoint_t *ep, - const ks_sockaddr_t *raddr, - uint8_t *transactionid, - ks_size_t transactionid_length, - long long errorcode, - const char *errorstr) -{ - ks_dht_message_t *error = NULL; - struct bencode *e = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(raddr); - ks_assert(transactionid); - ks_assert(errorstr); - - if (!ep && (ret = ks_dht_autoroute_check(dht, raddr, &ep)) != KS_STATUS_SUCCESS) goto done; - - ks_dht_message_create(&error, dht->pool, ep, raddr, KS_TRUE); - ks_assert(error); - - ben_dict_set(error->data, ben_blob("t", 1), ben_blob(transactionid, transactionid_length)); - ben_dict_set(error->data, ben_blob("y", 1), ben_blob("e", 1)); - - e = ben_list(); - ks_assert(e); - ben_dict_set(error->data, ben_blob("e", 1), e); - - - ben_list_append(e, ben_int(errorcode)); - ben_list_append(e, ben_blob(errorstr, strlen(errorstr))); - - ks_log(KS_LOG_DEBUG, "Sending message error %d\n", errorcode); - ks_q_push(dht->send_q, (void *)error); - - done: - if (ret != KS_STATUS_SUCCESS && error) ks_dht_message_destroy(&error); - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_error(ks_dht_t *dht, ks_dht_message_t *message) -{ - struct bencode *e; - struct bencode *ec; - struct bencode *es; - const char *et; - ks_size_t es_len; - long long errorcode; - char error[KS_DHT_MESSAGE_ERROR_MAX_SIZE]; - ks_dht_transaction_t *transaction; - uint32_t *tid; - uint32_t transactionid; - ks_dht_message_callback_t callback; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(message); - - e = ben_dict_get_by_str(message->data, "e"); - if (!e) { - ks_log(KS_LOG_DEBUG, "Message error missing required key 'e'\n"); - return KS_STATUS_FAIL; - } - ec = ben_list_get(e, 0); - es = ben_list_get(e, 1); - es_len = ben_str_len(es); - if (es_len >= KS_DHT_MESSAGE_ERROR_MAX_SIZE) { - ks_log(KS_LOG_DEBUG, "Message error value has an unexpectedly large size of %d\n", es_len); - ret = KS_STATUS_FAIL; - goto done; - } - errorcode = ben_int_val(ec); - et = ben_str_val(es); - - memcpy(error, et, es_len); - error[es_len] = '\0'; - - message->args = e; - - tid = (uint32_t *)message->transactionid; - transactionid = ntohl(*tid); - - ks_hash_read_lock(dht->transactions_hash); - transaction = ks_hash_search(dht->transactions_hash, (void *)&transactionid, KS_UNLOCKED); - ks_hash_read_unlock(dht->transactions_hash); - - if (!transaction) { - ks_log(KS_LOG_DEBUG, "Message error rejected with unknown transaction id %d\n", transactionid); - ret = KS_STATUS_FAIL; - goto done; - } - - if (!ks_addr_cmp(&message->raddr, &transaction->job->raddr)) { - ks_log(KS_LOG_DEBUG, - "Message error rejected due to spoofing from %s %d, expected %s %d\n", - message->raddr.host, - message->raddr.port, - transaction->job->raddr.host, - transaction->job->raddr.port); - ret = KS_STATUS_FAIL; - goto done; - } - transaction->job->result = KS_DHT_JOB_RESULT_ERROR; - transaction->job->error_code = errorcode; - transaction->job->error_description = ben_clone(es); - transaction->job->state = KS_DHT_JOB_STATE_COMPLETING; - transaction->finished = KS_TRUE; - - ks_hash_read_lock(dht->registry_error); - callback = (ks_dht_message_callback_t)(intptr_t)ks_hash_search(dht->registry_error, error, KS_UNLOCKED); - ks_hash_read_unlock(dht->registry_error); - - if (callback) ret = callback(dht, message); - else ks_log(KS_LOG_DEBUG, "Message error received for transaction id %d, error %d: %s\n", transactionid, errorcode, error); - - done: - return ret; -} - - -KS_DECLARE(void) ks_dht_ping(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_job_callback_t callback, void *data) -{ - ks_dht_job_t *job = NULL; - - ks_assert(dht); - ks_assert(raddr); - - //ks_log(KS_LOG_DEBUG, "Starting ping!\n"); - - ks_dht_job_create(&job, dht->pool, raddr, 3, data); - ks_assert(job); - - ks_dht_job_build_ping(job, ks_dht_query_ping, callback); - ks_dht_jobs_add(dht, job); -} - -KS_DECLARE(ks_status_t) ks_dht_query_ping(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_message_t *message = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - - if ((ret = ks_dht_query_setup(dht, - job, - "ping", - ks_dht_process_response_ping, - NULL, - &message, - NULL)) != KS_STATUS_SUCCESS) goto done; - - ks_log(KS_LOG_INFO, - "[%s %d] Ping query to %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - ks_q_push(dht->send_q, (void *)message); - - done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_query_ping(ks_dht_t *dht, ks_dht_message_t *message) -{ - ks_dht_message_t *response = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(message); - ks_assert(message->args); - - ks_log(KS_LOG_INFO, - "[%s %d] Ping query from %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - //ks_log(KS_LOG_DEBUG, "Message query ping is valid\n"); - - if ((ret = ks_dht_response_setup(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - &response, - NULL)) != KS_STATUS_SUCCESS) goto done; - - //ks_log(KS_LOG_DEBUG, "Sending message response ping\n"); - ks_q_push(dht->send_q, (void *)response); - - done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_response_ping(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - - ks_log(KS_LOG_INFO, - "[%s %d] Ping response from %s %d\n", - job->response->endpoint->addr.host, - job->response->endpoint->addr.port, - job->response->raddr.host, - job->response->raddr.port); - - //ks_log(KS_LOG_DEBUG, "Message response ping is reached\n"); - - // done: - return ret; -} - - -KS_DECLARE(void) ks_dht_findnode(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - ks_dht_nodeid_t *target) -{ - ks_dht_job_t *job = NULL; - - ks_assert(dht); - ks_assert(raddr); - ks_assert(target); - - ks_dht_job_create(&job, dht->pool, raddr, 3, data); - ks_assert(job); - - ks_dht_job_build_findnode(job, ks_dht_query_findnode, callback, target); - ks_dht_jobs_add(dht, job); -} - -KS_DECLARE(ks_status_t) ks_dht_query_findnode(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_transaction_t *transaction = NULL; - ks_dht_message_t *message = NULL; - struct bencode *a = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - - if ((ret = ks_dht_query_setup(dht, - job, - "find_node", - ks_dht_process_response_findnode, - &transaction, - &message, - &a)) != KS_STATUS_SUCCESS) goto done; - - //memcpy(transaction->target.id, job->query_target.id, KS_DHT_NODEID_SIZE); - //transaction->target = job->query_target; - - ben_dict_set(a, ben_blob("target", 6), ben_blob(job->query_target.id, KS_DHT_NODEID_SIZE)); - // Only request both v4 and v6 if we have both interfaces bound and are looking for our own node id, aka bootstrapping - if (dht->rt_ipv4 && dht->rt_ipv6 && !memcmp(dht->nodeid.id, job->query_target.id, KS_DHT_NODEID_SIZE)) { - struct bencode *want = ben_list(); - ben_list_append_str(want, "n4"); - ben_list_append_str(want, "n6"); - ben_dict_set(a, ben_blob("want", 4), want); - } - - ks_log(KS_LOG_INFO, - "[%s %d] Findnode query to %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - ks_q_push(dht->send_q, (void *)message); - - done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_query_findnode(ks_dht_t *dht, ks_dht_message_t *message) -{ - ks_dht_nodeid_t *target; - struct bencode *want; - ks_bool_t want4 = KS_FALSE; - ks_bool_t want6 = KS_FALSE; - ks_dht_message_t *response = NULL; - struct bencode *r = NULL; - uint8_t buffer4[1000]; - uint8_t buffer6[1000]; - ks_size_t buffer4_length = 0; - ks_size_t buffer6_length = 0; - ks_dhtrt_querynodes_t query; - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(message); - ks_assert(message->args); - - ks_log(KS_LOG_INFO, - "[%s %d] Findnode query from %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - if ((ret = ks_dht_utility_extract_nodeid(message->args, "target", &target)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query findnode args missing required key 'target'"); - goto done; - } - - want = ben_dict_get_by_str(message->args, "want"); - if (want) { - size_t want_len = ben_list_len(want); - for (size_t i = 0; i < want_len; ++i) { - struct bencode *iv = ben_list_get(want, i); - if (!ben_cmp_with_str(iv, "n4") && dht->rt_ipv4) want4 = KS_TRUE; - if (!ben_cmp_with_str(iv, "n6") && dht->rt_ipv6) want6 = KS_TRUE; - } - } - - if (!want4 && !want6) { - want4 = message->raddr.family == AF_INET; - want6 = message->raddr.family == AF_INET6; - } - - //ks_log(KS_LOG_DEBUG, "Message query find_node is valid\n"); - - - query.nodeid = *target; - query.type = KS_DHT_REMOTE; - query.max = 8; // @todo should be like KS_DHTRT_BUCKET_SIZE - if (want4) { - query.family = AF_INET; - ks_dhtrt_findclosest_nodes(dht->rt_ipv4, &query); - - for (int32_t i = 0; i < query.count; ++i) { - ks_dht_node_t *qn = query.nodes[i]; - - if ((ret = ks_dht_utility_compact_nodeinfo(&qn->nodeid, - &qn->addr, - buffer4, - &buffer4_length, - sizeof(buffer4))) != KS_STATUS_SUCCESS) { - ks_dhtrt_release_querynodes(&query); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal compact v4 nodeinfo error"); - goto done; - } - - ks_log(KS_LOG_DEBUG, - "Compacted ipv4 nodeinfo for %s (%s %d)\n", ks_dht_hex(qn->nodeid.id, id_buf, KS_DHT_NODEID_SIZE), qn->addr.host, qn->addr.port); - } - ks_dhtrt_release_querynodes(&query); - } - if (want6) { - query.family = AF_INET6; - ks_dhtrt_findclosest_nodes(dht->rt_ipv6, &query); - - for (int32_t i = 0; i < query.count; ++i) { - ks_dht_node_t *qn = query.nodes[i]; - - if ((ret = ks_dht_utility_compact_nodeinfo(&qn->nodeid, - &qn->addr, - buffer6, - &buffer6_length, - sizeof(buffer6))) != KS_STATUS_SUCCESS) { - ks_dhtrt_release_querynodes(&query); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal compact v6 nodeinfo error"); - goto done; - } - - ks_log(KS_LOG_DEBUG, - "Compacted ipv6 nodeinfo for %s (%s %d)\n", ks_dht_hex(qn->nodeid.id, id_buf, KS_DHT_NODEID_SIZE), qn->addr.host, qn->addr.port); - } - ks_dhtrt_release_querynodes(&query); - } - - if ((ret = ks_dht_response_setup(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - &response, - &r)) != KS_STATUS_SUCCESS) goto done; - - if (want4) ben_dict_set(r, ben_blob("nodes", 5), ben_blob(buffer4, buffer4_length)); - if (want6) ben_dict_set(r, ben_blob("nodes6", 6), ben_blob(buffer6, buffer6_length)); - - //ks_log(KS_LOG_DEBUG, "Sending message response find_node\n"); - ks_q_push(dht->send_q, (void *)response); - - done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_response_findnode(ks_dht_t *dht, ks_dht_job_t *job) -{ - struct bencode *n; - //ks_bool_t n4 = KS_FALSE; - //ks_bool_t n6 = KS_FALSE; - const uint8_t *nodes = NULL; - const uint8_t *nodes6 = NULL; - size_t nodes_size = 0; - size_t nodes6_size = 0; - size_t nodes_len = 0; - size_t nodes6_len = 0; - ks_dht_node_t *node = NULL; - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - - ks_log(KS_LOG_INFO, - "[%s %d] Findnode response from %s %d\n", - job->response->endpoint->addr.host, - job->response->endpoint->addr.port, - job->response->raddr.host, - job->response->raddr.port); - - n = ben_dict_get_by_str(job->response->args, "nodes"); - if (n && dht->rt_ipv4) { - //n4 = KS_TRUE; - nodes = (const uint8_t *)ben_str_val(n); - nodes_size = ben_str_len(n); - } - n = ben_dict_get_by_str(job->response->args, "nodes6"); - if (n && dht->rt_ipv6) { - //n6 = KS_TRUE; - nodes6 = (const uint8_t *)ben_str_val(n); - nodes6_size = ben_str_len(n); - } - - while (nodes_len < nodes_size) { - ks_dht_nodeid_t nid; - ks_sockaddr_t addr; - - addr.family = AF_INET; - if ((ret = ks_dht_utility_expand_nodeinfo(nodes, &nodes_len, nodes_size, &nid, &addr)) != KS_STATUS_SUCCESS) goto done; - - ks_log(KS_LOG_DEBUG, - "Expanded ipv4 nodeinfo for %s (%s %d)\n", - ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE), - addr.host, - addr.port); - - ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE)); - ks_dhtrt_create_node(dht->rt_ipv4, nid, KS_DHT_REMOTE, addr.host, addr.port, KS_DHTRT_CREATE_PING, &node); - job->response_nodes[job->response_nodes_count++] = node; - } - - while (nodes6_len < nodes6_size) { - ks_dht_nodeid_t nid; - ks_sockaddr_t addr; - - addr.family = AF_INET6; - if ((ret = ks_dht_utility_expand_nodeinfo(nodes6, &nodes6_len, nodes6_size, &nid, &addr)) != KS_STATUS_SUCCESS) goto done; - - ks_log(KS_LOG_DEBUG, - "Expanded ipv6 nodeinfo for %s (%s %d)\n", - ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE), - addr.host, - addr.port); - - ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE)); - ks_dhtrt_create_node(dht->rt_ipv6, nid, KS_DHT_REMOTE, addr.host, addr.port, KS_DHTRT_CREATE_PING, &node); - job->response_nodes6[job->response_nodes6_count++] = node; - } - - //ks_log(KS_LOG_DEBUG, "Message response find_node is reached\n"); - - done: - return ret; -} - - -KS_DECLARE(void) ks_dht_get(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - ks_dht_nodeid_t *target, - const uint8_t *salt, - ks_size_t salt_length) -{ - ks_dht_job_t *job = NULL; - - ks_assert(dht); - ks_assert(raddr); - ks_assert(target); - - ks_dht_job_create(&job, dht->pool, raddr, 3, data); - ks_assert(job); - - ks_dht_job_build_get(job, ks_dht_query_get, callback, target, salt, salt_length); - ks_dht_jobs_add(dht, job); -} - -KS_DECLARE(ks_status_t) ks_dht_query_get(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_message_t *message = NULL; - struct bencode *a = NULL; - ks_dht_storageitem_t *item = NULL; - - ks_assert(dht); - ks_assert(job); - - if (ks_dht_query_setup(dht, - job, - "get", - ks_dht_process_response_get, - NULL, - &message, - &a) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL; - - ks_hash_read_lock(dht->storageitems_hash); - item = ks_dht_storageitems_find(dht, &job->query_target); - if (item) ks_mutex_lock(item->mutex); - ks_hash_read_unlock(dht->storageitems_hash); - - if (item && item->mutable && item->seq > 0) ben_dict_set(a, ben_blob("seq", 3), ben_int(item->seq)); - ben_dict_set(a, ben_blob("target", 6), ben_blob(job->query_target.id, KS_DHT_NODEID_SIZE)); - - ks_log(KS_LOG_INFO, - "[%s %d] Get query to %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - if (item) { - ks_dht_storageitem_dereference(item); - ks_mutex_unlock(item->mutex); - } - ks_q_push(dht->send_q, (void *)message); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_dht_process_query_get(ks_dht_t *dht, ks_dht_message_t *message) -{ - ks_dht_nodeid_t *target; - struct bencode *seq; - int64_t sequence = -1; - ks_bool_t sequence_snuffed = KS_FALSE; - ks_dht_token_t token; - ks_dht_storageitem_t *item = NULL; - ks_dht_message_t *response = NULL; - struct bencode *r = NULL; - ks_dhtrt_querynodes_t query; - uint8_t buffer4[1000]; - uint8_t buffer6[1000]; - ks_size_t buffer4_length = 0; - ks_size_t buffer6_length = 0; - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(message); - ks_assert(message->args); - - ks_log(KS_LOG_INFO, - "[%s %d] Get query from %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - if ((ret = ks_dht_utility_extract_nodeid(message->args, "target", &target)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query get args missing required key 'target'"); - goto done; - } - - seq = ben_dict_get_by_str(message->args, "seq"); - if (seq) sequence = ben_int_val(seq); - - //ks_log(KS_LOG_DEBUG, "Message query get is valid\n"); - - ks_dht_token_generate(dht->token_secret_current, &message->raddr, target, &token); - - ks_hash_read_lock(dht->storageitems_hash); - item = ks_dht_storageitems_find(dht, target); - if (item) { - ks_mutex_lock(item->mutex); - item->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - } - ks_hash_read_unlock(dht->storageitems_hash); - - sequence_snuffed = item && sequence >= 0 && item->seq <= sequence; - - query.nodeid = *target; - query.type = KS_DHT_REMOTE; - query.max = 8; // should be like KS_DHTRT_BUCKET_SIZE - if (dht->rt_ipv4) { - query.family = AF_INET; - - ks_dhtrt_findclosest_nodes(dht->rt_ipv4, &query); - for (int32_t i = 0; i < query.count; ++i) { - ks_dht_node_t *qn = query.nodes[i]; - - if ((ret = ks_dht_utility_compact_nodeinfo(&qn->nodeid, - &qn->addr, - buffer4, - &buffer4_length, - sizeof(buffer4))) != KS_STATUS_SUCCESS) { - ks_dhtrt_release_querynodes(&query); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal compact v4 nodeinfo error"); - goto done; - } - - ks_log(KS_LOG_DEBUG, - "Compacted ipv4 nodeinfo for %s (%s %d)\n", ks_dht_hex(qn->nodeid.id, id_buf, KS_DHT_NODEID_SIZE), qn->addr.host, qn->addr.port); - } - ks_dhtrt_release_querynodes(&query); - } - if (dht->rt_ipv6) { - query.family = AF_INET6; - - ks_dhtrt_findclosest_nodes(dht->rt_ipv6, &query); - for (int32_t i = 0; i < query.count; ++i) { - ks_dht_node_t *qn = query.nodes[i]; - - if ((ret = ks_dht_utility_compact_nodeinfo(&qn->nodeid, - &qn->addr, - buffer6, - &buffer6_length, - sizeof(buffer6))) != KS_STATUS_SUCCESS) { - ks_dhtrt_release_querynodes(&query); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal compact v6 nodeinfo error"); - goto done; - } - - ks_log(KS_LOG_DEBUG, - "Compacted ipv6 nodeinfo for %s (%s %d)\n", ks_dht_hex(qn->nodeid.id, id_buf, KS_DHT_NODEID_SIZE), qn->addr.host, qn->addr.port); - } - ks_dhtrt_release_querynodes(&query); - } - - - if ((ret = ks_dht_response_setup(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - &response, - &r)) != KS_STATUS_SUCCESS) goto done; - - ben_dict_set(r, ben_blob("token", 5), ben_blob(token.token, KS_DHT_TOKEN_SIZE)); - if (item) { - if (item->mutable) { - if (!sequence_snuffed) { - ben_dict_set(r, ben_blob("k", 1), ben_blob(item->pk.key, KS_DHT_STORAGEITEM_PKEY_SIZE)); - ben_dict_set(r, ben_blob("sig", 3), ben_blob(item->sig.sig, KS_DHT_STORAGEITEM_SIGNATURE_SIZE)); - } - ben_dict_set(r, ben_blob("seq", 3), ben_int(item->seq)); - } - if (!sequence_snuffed) ben_dict_set(r, ben_blob("v", 1), ben_clone(item->v)); - } - if (dht->rt_ipv4) ben_dict_set(r, ben_blob("nodes", 5), ben_blob(buffer4, buffer4_length)); - if (dht->rt_ipv6) ben_dict_set(r, ben_blob("nodes6", 6), ben_blob(buffer6, buffer6_length)); - - //ks_log(KS_LOG_DEBUG, "Sending message response get\n"); - ks_q_push(dht->send_q, (void *)response); - - done: - if (item) { - ks_dht_storageitem_dereference(item); - ks_mutex_unlock(item->mutex); - } - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_response_get(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_storageitem_t *item = NULL; - ks_dht_token_t *token = NULL; - ks_dht_storageitem_pkey_t *k = NULL; - ks_dht_storageitem_signature_t *sig = NULL; - struct bencode *seq; - int64_t sequence = -1; - struct bencode *v = NULL; - //ks_size_t v_len = 0; - struct bencode *n; - ks_dht_node_t *node = NULL; - const uint8_t *nodes = NULL; - const uint8_t *nodes6 = NULL; - size_t nodes_size = 0; - size_t nodes6_size = 0; - size_t nodes_len = 0; - size_t nodes6_len = 0; - char id_buf[KS_DHT_NODEID_SIZE * 2 + 1]; - ks_bool_t storageitems_locked = KS_FALSE; - ks_dht_storageitem_t *olditem = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - - ks_log(KS_LOG_INFO, - "[%s %d] Get response from %s %d\n", - job->response->endpoint->addr.host, - job->response->endpoint->addr.port, - job->response->raddr.host, - job->response->raddr.port); - - if ((ret = ks_dht_utility_extract_token(job->response->args, "token", &token)) != KS_STATUS_SUCCESS) goto done; - job->response_token = *token; - - if ((ret = ks_dht_utility_extract_storageitem_pkey(job->response->args, KS_TRUE, "k", &k)) != KS_STATUS_SUCCESS) goto done; - if ((ret = ks_dht_utility_extract_storageitem_signature(job->response->args, KS_TRUE, "sig", &sig)) != KS_STATUS_SUCCESS) goto done; - - seq = ben_dict_get_by_str(job->response->args, "seq"); - if (seq) { - sequence = ben_int_val(seq); - job->response_hasitem = KS_TRUE; - job->response_seq = sequence; - } - - if (seq && ((k && !sig) || (!k && sig))) { - ks_log(KS_LOG_DEBUG, "Must provide both k and sig for mutable data"); - ret = KS_STATUS_ARG_INVALID; - goto done; - } - - v = ben_dict_get_by_str(job->response->args, "v"); - if (v) job->response_hasitem = KS_TRUE; - //if (v) v_len = ben_str_len(v); - - n = ben_dict_get_by_str(job->response->args, "nodes"); - if (n && dht->rt_ipv4) { - nodes = (const uint8_t *)ben_str_val(n); - nodes_size = ben_str_len(n); - } - n = ben_dict_get_by_str(job->response->args, "nodes6"); - if (n && dht->rt_ipv6) { - nodes6 = (const uint8_t *)ben_str_val(n); - nodes6_size = ben_str_len(n); - } - - //ks_log(KS_LOG_DEBUG, "Message response get is reached\n"); - - while (nodes_len < nodes_size) { - ks_dht_nodeid_t nid; - ks_sockaddr_t addr; - - addr.family = AF_INET; - if ((ret = ks_dht_utility_expand_nodeinfo(nodes, &nodes_len, nodes_size, &nid, &addr)) != KS_STATUS_SUCCESS) goto done; - - ks_log(KS_LOG_DEBUG, - "Expanded ipv4 nodeinfo for %s (%s %d)\n", - ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE), - addr.host, - addr.port); - - ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE)); - ks_dhtrt_create_node(dht->rt_ipv4, nid, KS_DHT_REMOTE, addr.host, addr.port, KS_DHTRT_CREATE_PING, &node); - job->response_nodes[job->response_nodes_count++] = node; - } - while (nodes6_len < nodes6_size) { - ks_dht_nodeid_t nid; - ks_sockaddr_t addr; - - addr.family = AF_INET6; - if ((ret = ks_dht_utility_expand_nodeinfo(nodes6, &nodes6_len, nodes6_size, &nid, &addr)) != KS_STATUS_SUCCESS) goto done; - - ks_log(KS_LOG_DEBUG, - "Expanded ipv6 nodeinfo for %s (%s %d)\n", - ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE), - addr.host, - addr.port); - - ks_log(KS_LOG_DEBUG, "Creating node %s\n", ks_dht_hex(nid.id, id_buf, KS_DHT_NODEID_SIZE)); - ks_dhtrt_create_node(dht->rt_ipv6, nid, KS_DHT_REMOTE, addr.host, addr.port, KS_DHTRT_CREATE_PING, &node); - job->response_nodes6[job->response_nodes6_count++] = node; - } - - ks_hash_write_lock(dht->storageitems_hash); - storageitems_locked = KS_TRUE; - olditem = ks_dht_storageitems_find(dht, &job->query_target); - if (olditem) ks_mutex_lock(olditem->mutex); - - if (v) { - ks_dht_nodeid_t tmptarget; - - if (!seq) { - // immutable - if ((ret = ks_dht_storageitem_target_immutable_internal(v, &tmptarget)) != KS_STATUS_SUCCESS) goto done; - if (memcmp(tmptarget.id, job->query_target.id, KS_DHT_NODEID_SIZE) != 0) { - ks_log(KS_LOG_DEBUG, "Immutable data hash does not match requested target id\n"); - ret = KS_STATUS_FAIL; - goto done; - } - if (olditem) olditem->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - else { - ks_dht_storageitem_create_immutable_internal(&item, dht->pool, &tmptarget, v, KS_TRUE); - ks_assert(item); - } - } else { - // mutable - if ((ret = ks_dht_storageitem_target_mutable_internal(k, job->query_salt, &tmptarget)) != KS_STATUS_SUCCESS) goto done; - if (memcmp(tmptarget.id, job->query_target.id, KS_DHT_NODEID_SIZE) != 0) { - ks_log(KS_LOG_DEBUG, "Mutable data hash does not match requested target id\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - if (!ks_dht_storageitem_signature_verify(sig, k, job->query_salt, seq, v)) { - ks_log(KS_LOG_DEBUG, "Mutable data signature failed to verify\n"); - ret = KS_STATUS_FAIL; - goto done; - } - ks_log(KS_LOG_DEBUG, "Signature verified for %s\n", ks_dht_hex(tmptarget.id, id_buf, KS_DHT_NODEID_SIZE)); - if (olditem) { - if (olditem->seq > sequence) { - goto done; - } - if (olditem->seq == sequence) { - if (ben_cmp(olditem->v, v) != 0) { - goto done; - } - } else { - ks_dht_storageitem_update_mutable(olditem, v, sequence, sig); - if (olditem->callback) olditem->callback(dht, olditem); - } - olditem->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - } - else { - ks_dht_storageitem_create_mutable_internal(&item, dht->pool, &tmptarget, v, KS_TRUE, k, job->query_salt, KS_TRUE, sequence, sig); - ks_assert(item); - } - } - if (item) ks_hash_insert(dht->storageitems_hash, item->id.id, item); - } else if (seq && olditem && olditem->seq == sequence) olditem->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - - if (item) job->response_storageitem = item; - else if (olditem) job->response_storageitem = olditem; - - if (job->response_storageitem) ks_dht_storageitem_reference(job->response_storageitem); - - done: - if (olditem) { - ks_dht_storageitem_dereference(olditem); - ks_mutex_unlock(olditem->mutex); - } - if (item) ks_dht_storageitem_dereference(item); - if (ret != KS_STATUS_SUCCESS) { - } - if (storageitems_locked) ks_hash_write_unlock(dht->storageitems_hash); - return ret; -} - -KS_DECLARE(void) ks_dht_put(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - ks_dht_token_t *token, - int64_t cas, - ks_dht_storageitem_t *item) -{ - ks_dht_job_t *job = NULL; - - ks_assert(dht); - ks_assert(raddr); - ks_assert(token); - ks_assert(item); - - ks_dht_job_create(&job, dht->pool, raddr, 3, data); - ks_assert(job); - - ks_dht_job_build_put(job, ks_dht_query_put, callback, token, cas, item); - ks_dht_jobs_add(dht, job); -} - -KS_DECLARE(ks_status_t) ks_dht_query_put(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_message_t *message = NULL; - struct bencode *a = NULL; - - ks_assert(dht); - ks_assert(job); - - if (ks_dht_query_setup(dht, - job, - "put", - ks_dht_process_response_put, - NULL, - &message, - &a) != KS_STATUS_SUCCESS) return KS_STATUS_FAIL; - - if (job->query_storageitem->mutable) { - if (job->query_cas > 0) ben_dict_set(a, ben_blob("cas", 3), ben_int(job->query_cas)); - ben_dict_set(a, ben_blob("k", 1), ben_blob(job->query_storageitem->pk.key, KS_DHT_STORAGEITEM_PKEY_SIZE)); - if (job->query_storageitem->salt) ben_dict_set(a, ben_blob("salt", 4), ben_clone(job->query_storageitem->salt)); - ben_dict_set(a, ben_blob("seq", 3), ben_int(job->query_storageitem->seq)); - ben_dict_set(a, ben_blob("sig", 3), ben_blob(job->query_storageitem->sig.sig, KS_DHT_STORAGEITEM_SIGNATURE_SIZE)); - } - ben_dict_set(a, ben_blob("token", 5), ben_blob(job->query_token.token, KS_DHT_TOKEN_SIZE)); - ben_dict_set(a, ben_blob("v", 1), ben_clone(job->query_storageitem->v)); - - ks_log(KS_LOG_INFO, - "[%s %d] Put query to %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - ks_q_push(dht->send_q, (void *)message); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_dht_process_query_put(ks_dht_t *dht, ks_dht_message_t *message) -{ - ks_dht_token_t *token = NULL; - ks_dht_storageitem_pkey_t *k = NULL; - ks_dht_storageitem_signature_t *sig = NULL; - struct bencode *salt = NULL; - struct bencode *seq = NULL; - int64_t sequence = -1; - struct bencode *cas = NULL; - int64_t cas_seq = -1; - struct bencode *v = NULL; - //ks_size_t v_len = 0; - ks_bool_t storageitems_locked = KS_FALSE; - ks_dht_storageitem_t *item = NULL; - ks_dht_storageitem_t *olditem = NULL; - ks_dht_nodeid_t target; - ks_dht_message_t *response = NULL; - struct bencode *r = NULL; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(message); - ks_assert(message->args); - - ks_log(KS_LOG_INFO, - "[%s %d] Put query from %s %d\n", - message->endpoint->addr.host, - message->endpoint->addr.port, - message->raddr.host, - message->raddr.port); - - if ((ret = ks_dht_utility_extract_token(message->args, "token", &token)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query put args missing required key 'token'"); - goto done; - } - - if ((ret = ks_dht_utility_extract_storageitem_pkey(message->args, KS_TRUE, "k", &k)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query put 'k' is malformed"); - goto done; - } - if ((ret = ks_dht_utility_extract_storageitem_signature(message->args, KS_TRUE, "sig", &sig)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query put 'sig' is malformed"); - goto done; - } - - salt = ben_dict_get_by_str(message->args, "salt"); - if (salt && ben_str_len(salt) > KS_DHT_STORAGEITEM_SALT_MAX_SIZE) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 207, - "Message query put 'salt' is too large"); - goto done; - } - - seq = ben_dict_get_by_str(message->args, "seq"); - if (seq) sequence = ben_int_val(seq); - - cas = ben_dict_get_by_str(message->args, "cas"); - if (cas) cas_seq = ben_int_val(cas); - - if (seq && (!k || !sig)) { - ks_log(KS_LOG_DEBUG, "Must provide both k and sig for mutable data\n"); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query put for mutable data must include both 'k' and 'sig'"); - ret = KS_STATUS_ARG_INVALID; - goto done; - } - - v = ben_dict_get_by_str(message->args, "v"); - if (!v) { - ks_log(KS_LOG_DEBUG, "Must provide v\n"); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query put args missing required key 'v'"); - ret = KS_STATUS_ARG_INVALID; - goto done; - } - //v_len = ben_str_len(v); - - if (!seq) { - // immutable - if ((ret = ks_dht_storageitem_target_immutable_internal(v, &target)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal storage item target immutable error"); - goto done; - } - } else { - // mutable - if ((ret = ks_dht_storageitem_target_mutable_internal(k, salt, &target)) != KS_STATUS_SUCCESS) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 202, - "Internal storage item target mutable error"); - goto done; - } - } - - ks_hash_write_lock(dht->storageitems_hash); - storageitems_locked = KS_TRUE; - - olditem = ks_dht_storageitems_find(dht, &target); - if (olditem) ks_mutex_lock(olditem->mutex); - - if (!ks_dht_token_verify(dht, &message->raddr, &target, token)) { - ks_log(KS_LOG_DEBUG, "Invalid token\n"); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 203, - "Message query put token is invalid"); - ret = KS_STATUS_FAIL; - goto done; - } - - //ks_log(KS_LOG_DEBUG, "Message query put is valid\n"); - - - if (!seq) { - // immutable - if (olditem) olditem->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - else { - ks_dht_storageitem_create_immutable_internal(&item, dht->pool, &target, v, KS_TRUE); - ks_assert(item); - } - } else { - // mutable - if (!ks_dht_storageitem_signature_verify(sig, k, salt, seq, v)) { - ks_log(KS_LOG_DEBUG, "Mutable data signature failed to verify\n"); - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 206, - "Message query put signature is invalid"); - ret = KS_STATUS_FAIL; - goto done; - } - - if (olditem) { - if (cas && olditem->seq != cas_seq) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 301, - "Message query put cas mismatch"); - goto done; - } - if (olditem->seq > sequence) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 302, - "Message query put sequence is less than current"); - goto done; - } - if (olditem->seq == sequence) { - if (ben_cmp(olditem->v, v) != 0) { - ks_dht_error(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - 201, - "Message query put sequence is equal to current but values are different"); - goto done; - } - } else { - ks_dht_storageitem_update_mutable(olditem, v, sequence, sig); - if (olditem->callback) olditem->callback(dht, olditem); - } - olditem->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - } - else { - ks_dht_storageitem_create_mutable_internal(&item, dht->pool, &target, v, KS_TRUE, k, salt, KS_TRUE, sequence, sig); - ks_assert(item); - } - } - if (item) ks_hash_insert(dht->storageitems_hash, item->id.id, item); - - if ((ret = ks_dht_response_setup(dht, - message->endpoint, - &message->raddr, - message->transactionid, - message->transactionid_length, - &response, - &r)) != KS_STATUS_SUCCESS) goto done; - - //ks_log(KS_LOG_DEBUG, "Sending message response put\n"); - ks_q_push(dht->send_q, (void *)response); - - //if (dht->rt_ipv4) ks_dht_distribute(dht, AF_INET, NULL, NULL, 0, olditem ? olditem : item); - //if (dht->rt_ipv6) ks_dht_distribute(dht, AF_INET6, NULL, NULL, 0, olditem ? olditem : item); - - done: - if (olditem) { - ks_dht_storageitem_dereference(olditem); - ks_mutex_unlock(olditem->mutex); - } - if (item) ks_dht_storageitem_dereference(item); - if (ret != KS_STATUS_SUCCESS) { - if (item) ks_hash_remove(dht->storageitems_hash, item->id.id); - } - if (storageitems_locked) ks_hash_write_unlock(dht->storageitems_hash); - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_process_response_put(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(dht); - ks_assert(job); - - ks_log(KS_LOG_INFO, - "[%s %d] Put response from %s %d\n", - job->response->endpoint->addr.host, - job->response->endpoint->addr.port, - job->response->raddr.host, - job->response->raddr.port); - - //ks_log(KS_LOG_DEBUG, "Message response put is reached\n"); - - // done: - return ret; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_bucket.c b/libs/libblade/src/dht/ks_dht_bucket.c deleted file mode 100644 index de7324bcbd..0000000000 --- a/libs/libblade/src/dht/ks_dht_bucket.c +++ /dev/null @@ -1,2004 +0,0 @@ -/* - * Copyright (c) 2016, FreeSWITCH Solutions 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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. - */ - -/* # pragma GCC optimize ("O0") */ - - -#include "ks_dht.h" - - -/* change for testing */ -#define KS_DHT_BUCKETSIZE 20 -#define KS_DHTRT_INACTIVETIME (10*60) -#define KS_DHTRT_EXPIREDTIME (15*60) -#define KS_DHTRT_MAXPING 3 -#define KS_DHTRT_PROCESSTABLE_INTERVAL (5*60) -#define KS_DHTRT_PROCESSTABLE_SHORTINTERVAL120 (2*60) -#define KS_DHTRT_PROCESSTABLE_SHORTINTERVAL60 (1*60) -#define KS_DHTRT_RECYCLE_NODE_THRESHOLD 100 - -/* peer flags */ -#define DHTPEER_DUBIOUS 0 -#define DHTPEER_EXPIRED 1 -#define DHTPEER_ACTIVE 2 - - -typedef uint8_t ks_dhtrt_nodeid_t[KS_DHT_NODEID_SIZE]; - -/* internal structures */ -typedef struct ks_dhtrt_bucket_entry_s { - ks_time_t tyme; - ks_time_t ping_tyme; -// uint8_t id[KS_DHT_NODEID_SIZE]; - ks_dht_node_t *gptr; /* ptr to peer */ - uint8_t inuse; - uint8_t outstanding_pings; - uint8_t flags; /* active, suspect, expired */ - uint8_t touched; /* did we ever get a touch */ -} ks_dhtrt_bucket_entry_t; - -typedef struct ks_dhtrt_bucket_s { - ks_dhtrt_bucket_entry_t entries[KS_DHT_BUCKETSIZE]; - uint8_t count; - ks_time_t findtyme; /* last time a find was generated */ - uint8_t expired_count; - ks_rwl_t *lock; /* lock for safe traversal of the entry array */ -} ks_dhtrt_bucket_t; - - -#define BHF_LEFT 0x80 - -typedef struct ks_dhtrt_bucket_header_s { - struct ks_dhtrt_bucket_header_s * parent; - struct ks_dhtrt_bucket_header_s * left; - struct ks_dhtrt_bucket_header_s * right; - struct ks_dhtrt_bucket_header_s * left1bit; - struct ks_dhtrt_bucket_header_s * right1bit; - ks_dhtrt_bucket_t * bucket; - ks_time_t tyme; /* last processed time */ - unsigned char mask[KS_DHT_NODEID_SIZE]; /* node id mask */ - unsigned char flags; -} ks_dhtrt_bucket_header_t; - -typedef struct ks_dhtrt_deletednode_s { - ks_dht_node_t* node; - struct ks_dhtrt_deletednode_s *next; -} ks_dhtrt_deletednode_t; - -typedef struct ks_dhtrt_internal_s { - uint8_t localid[KS_DHT_NODEID_SIZE]; - ks_dhtrt_bucket_header_t *buckets; /* root bucketheader */ - ks_dht_t *dht; - ks_rwl_t *lock; /* lock for safe traversal of the tree */ - ks_time_t last_process_table; - ks_time_t next_process_table_delta; - ks_mutex_t *deleted_node_lock; - ks_dhtrt_deletednode_t *deleted_node; - ks_dhtrt_deletednode_t *free_node_ex; - uint32_t deleted_count; - uint32_t bucket_count; - uint32_t header_count; -} ks_dhtrt_internal_t; - -typedef struct ks_dhtrt_xort_s { - unsigned int ix; /* index of bucket array */ - unsigned char xor[KS_DHT_NODEID_SIZE]; /* corresponding xor value */ - unsigned int nextix; -} ks_dhtrt_xort_t; - -typedef struct ks_dhtrt_sortedxors_s { - ks_dhtrt_bucket_header_t *bheader; - ks_dhtrt_xort_t xort[KS_DHT_BUCKETSIZE]; - unsigned char hixor[KS_DHT_NODEID_SIZE]; - unsigned int startix; - unsigned int count; - struct ks_dhtrt_sortedxors_s* next; -} ks_dhtrt_sortedxors_t; - - -/* --- static functions ---- */ - -static -ks_dhtrt_bucket_header_t *ks_dhtrt_create_bucketheader( - ks_pool_t *pool, - ks_dhtrt_bucket_header_t *parent, - unsigned char *mask); -static -ks_dhtrt_bucket_t *ks_dhtrt_create_bucket(ks_pool_t *pool); -static -ks_dhtrt_bucket_header_t *ks_dhtrt_find_bucketheader(ks_dhtrt_routetable_t *table, ks_dhtrt_nodeid_t id); -static -ks_dhtrt_bucket_header_t *ks_dhtrt_find_relatedbucketheader(ks_dhtrt_bucket_header_t *header, ks_dhtrt_nodeid_t id); -static -ks_dhtrt_bucket_entry_t *ks_dhtrt_find_bucketentry(ks_dhtrt_bucket_header_t *header, ks_dhtrt_nodeid_t id); - -static -void ks_dhtrt_split_bucket(ks_dhtrt_bucket_header_t *original, ks_dhtrt_bucket_header_t *left, ks_dhtrt_bucket_header_t *right); -static -ks_dht_node_t *ks_dhtrt_find_nodeid(ks_dhtrt_bucket_t *bucket, ks_dhtrt_nodeid_t nodeid); - - -static -void ks_dhtrt_shiftright(uint8_t *id); -static -void ks_dhtrt_shiftleft(uint8_t *id); -static -void ks_dhtrt_midmask(uint8_t *leftid, uint8_t *rightid, uint8_t *midpt); - -static -void ks_dhtrt_xor(const uint8_t *id1, const uint8_t *id2, uint8_t *xor); -static -int ks_dhtrt_ismasked(const uint8_t *id1, const uint8_t *mask); -static -void ks_dhtrt_queue_node_fordelete(ks_dhtrt_routetable_t *table, ks_dht_node_t* node); -static -void ks_dhtrt_process_deleted(ks_dhtrt_routetable_t *table, int8_t all); - -static -ks_dht_node_t *ks_dhtrt_make_node(ks_dhtrt_routetable_t *table); -static -ks_status_t ks_dhtrt_insert_node(ks_dhtrt_routetable_t *table, ks_dht_node_t *node, enum ks_create_node_flags_t flags); -static -ks_dhtrt_bucket_entry_t* ks_dhtrt_insert_id(ks_dhtrt_bucket_t *bucket, ks_dht_node_t *node); -static -ks_status_t ks_dhtrt_delete_id(ks_dhtrt_bucket_t *bucket, ks_dhtrt_nodeid_t id); -static -char *ks_dhtrt_printableid(uint8_t *id, char *buffer); - -static -uint8_t ks_dhtrt_findclosest_locked_nodes(ks_dhtrt_routetable_t *table, ks_dhtrt_querynodes_t *query); -static -uint8_t ks_dhtrt_load_query(ks_dhtrt_querynodes_t *query, ks_dhtrt_sortedxors_t *xort); -static -uint8_t ks_dhtrt_findclosest_bucketnodes(unsigned char *nodeid, - enum ks_dht_nodetype_t type, - enum ks_afflags_t family, - ks_dhtrt_bucket_header_t *header, - ks_dhtrt_sortedxors_t *xors, - unsigned char *hixor, - unsigned int max); - -static -void ks_dhtrt_ping(ks_dhtrt_internal_t *internal, ks_dhtrt_bucket_entry_t *entry); -static -void ks_dhtrt_find(ks_dhtrt_routetable_t *table, ks_dhtrt_internal_t *internal, ks_dht_nodeid_t *nodeid); - - -/* debugging */ -#define KS_DHT_DEBUGPRINTF_ -/* very verbose */ -/* # define KS_DHT_DEBUGPRINTFX_ */ -/* debug locking */ -/* #define KS_DHT_DEBUGLOCKPRINTF_ */ - -KS_DECLARE(ks_status_t) ks_dhtrt_initroute(ks_dhtrt_routetable_t **tableP, - ks_dht_t *dht, - ks_pool_t *pool) -{ - - unsigned char initmask[KS_DHT_NODEID_SIZE]; - memset(initmask, 0xff, sizeof(initmask)); - - ks_dhtrt_routetable_t *table = ks_pool_alloc(pool, sizeof(ks_dhtrt_routetable_t)); - - ks_dhtrt_internal_t *internal = ks_pool_alloc(pool, sizeof(ks_dhtrt_internal_t)); - - ks_rwl_create(&internal->lock, pool); - internal->dht = dht; - internal->next_process_table_delta = KS_DHTRT_PROCESSTABLE_INTERVAL; - ks_mutex_create(&internal->deleted_node_lock, KS_MUTEX_FLAG_DEFAULT, pool); - table->internal = internal; - - /* initialize root bucket */ - ks_dhtrt_bucket_header_t *initial_header = ks_dhtrt_create_bucketheader(pool, 0, initmask); - - initial_header->flags = BHF_LEFT; /* fake left to allow splitting */ - internal->buckets = initial_header; - initial_header->bucket = ks_dhtrt_create_bucket(pool); - internal->header_count = 1; - internal->bucket_count = 1; - table->pool = pool; - - *tableP = table; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(void) ks_dhtrt_deinitroute(ks_dhtrt_routetable_t **tableP) -{ - /* @todo*/ - ks_dhtrt_routetable_t* table = *tableP; - - if (!table || !table->internal) { - return; - } - - ks_dhtrt_internal_t* internal = table->internal; - ks_rwl_write_lock(internal->lock); /* grab write lock */ - ks_dhtrt_process_deleted(table, 1); - table->internal = NULL; /* make sure no other threads get in */ - ks_pool_t *pool = table->pool; - - - ks_dhtrt_bucket_header_t *header = internal->buckets; - ks_dhtrt_bucket_header_t *last_header; - ks_dhtrt_bucket_header_t *stack[KS_DHT_NODEID_SIZE * 8]; - int stackix=0; - - while (header) { - stack[stackix++] = header; - - if (header->bucket) { - ks_pool_free(pool, &header->bucket); - header->bucket = NULL; - } - last_header = header; - header = header->left; - - if (header == 0 && stackix > 1) { - stackix -= 2; - header = stack[stackix]; - header = header->right; -#ifdef KS_DHT_DEBUGLOCKPRINTFX_ - char buf[100]; - ks_log(KS_LOG_DEBUG,"deinit: freeing bucket header %s\n", ks_dhtrt_printableid(last_header->mask, buf)); -#endif - ks_pool_free(pool, &last_header); - } - } - - ks_pool_free(pool, &internal); - ks_pool_free(pool, &table); - *tableP = NULL; - - return; -} - - - -KS_DECLARE(ks_status_t) ks_dhtrt_create_node( ks_dhtrt_routetable_t *table, - ks_dht_nodeid_t nodeid, - enum ks_dht_nodetype_t type, - char *ip, - unsigned short port, - enum ks_create_node_flags_t flags, - ks_dht_node_t **node) -{ - if (!table || !table->internal) { - return KS_STATUS_FAIL; - } - - ks_dht_node_t *tnode; - ks_dhtrt_internal_t* internal = table->internal; - - ks_rwl_read_lock(internal->lock); /* grab write lock and insert */ - - ks_dhtrt_bucket_header_t *header = ks_dhtrt_find_bucketheader(table, nodeid.id); - assert(header != NULL); /* should always find a header */ - - ks_dhtrt_bucket_entry_t *bentry = ks_dhtrt_find_bucketentry(header, nodeid.id); - - if (bentry != 0) { - - ks_rwl_read_lock(header->bucket->lock); - - bentry->tyme = ks_time_now_sec(); - - /* touch */ - if (flags == KS_DHTRT_CREATE_TOUCH) { - bentry->outstanding_pings = 0; - bentry->touched = 1; - if (bentry->flags == DHTPEER_EXPIRED) { - --header->bucket->expired_count; - } - } - - if (bentry->touched) { - bentry->flags = DHTPEER_ACTIVE; - } - - /* ping */ - if (!bentry->touched && !bentry->outstanding_pings) { - ks_dhtrt_ping(internal, bentry); - } - - tnode = bentry->gptr; - - ks_rwl_read_unlock(header->bucket->lock); - ks_rwl_read_lock( tnode->reflock); - ks_rwl_read_unlock(internal->lock); - - (*node) = tnode; - return KS_STATUS_SUCCESS; - } - ks_rwl_read_unlock(internal->lock); - - tnode = ks_dhtrt_make_node(table); - tnode->table = table; - - enum ks_afflags_t family = AF_INET; - - for (int i = 0; i < 5; ++i) { - if (ip[i] == ':') { - family = AF_INET6; - break; - } else if (ip[i] == '.') { - family = AF_INET; - break; - } - } - - memcpy(tnode->nodeid.id, nodeid.id, KS_DHT_NODEID_SIZE); - tnode->type = type; - - if (( ks_addr_set(&tnode->addr, ip, port, family) != KS_STATUS_SUCCESS) || - ( ks_rwl_create(&tnode->reflock, table->pool) != KS_STATUS_SUCCESS)) { - ks_pool_free(table->pool, &tnode); - ks_rwl_read_unlock(internal->lock); - return KS_STATUS_FAIL; - } - - ks_status_t s = ks_dhtrt_insert_node(table, tnode, flags); - - if (tnode && s == KS_STATUS_SUCCESS) { - ks_rwl_read_lock( tnode->reflock); - } - - (*node) = tnode; - - return s; -} - -KS_DECLARE(ks_status_t) ks_dhtrt_delete_node(ks_dhtrt_routetable_t *table, ks_dht_node_t *node) -{ - char buf[51]; - if (!table || !table->internal) { - return KS_STATUS_FAIL; - } - - ks_status_t s = KS_STATUS_FAIL; - ks_dhtrt_internal_t* internal = table->internal; - - ks_rwl_read_lock(internal->lock); /* grab read lock */ - ks_dhtrt_bucket_header_t *header = ks_dhtrt_find_bucketheader(table, node->nodeid.id); - - if (header != 0) { - ks_dhtrt_bucket_t *bucket = header->bucket; - - if (bucket != 0) { /* we found a bucket*/ -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Delete node: LOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); -#endif - ks_rwl_write_lock(bucket->lock); - s = ks_dhtrt_delete_id(bucket, node->nodeid.id); - ks_log(KS_LOG_DEBUG, "Delete node: UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); - - ks_rwl_write_unlock(bucket->lock); - } - } - - ks_rwl_read_unlock(internal->lock); /* release write lock */ - /* at this point no subsequent find/query will return the node */ - - if (s == KS_STATUS_FAIL) { - ks_log(KS_LOG_DEBUG, "Delete node: node not found %s\n", ks_dhtrt_printableid(header->mask, buf)); - return KS_STATUS_FAIL; /* cannot delete what we cannot find */ - } - - ks_dhtrt_queue_node_fordelete(table, node); - return s; -} - -static -ks_status_t ks_dhtrt_insert_node(ks_dhtrt_routetable_t *table, ks_dht_node_t *node, enum ks_create_node_flags_t flags) -{ - char buf[51]; - if (!table || !table->internal) { - return KS_STATUS_FAIL; - } - - ks_dhtrt_internal_t* internal = table->internal; - ks_dhtrt_bucket_t *bucket = 0; - - int insanity = 0; - - ks_rwl_write_lock(internal->lock); - ks_dhtrt_bucket_header_t *header = ks_dhtrt_find_bucketheader(table, node->nodeid.id); - assert(header != NULL); /* should always find a header */ - - bucket = header->bucket; - - if (bucket == 0) { - ks_rwl_write_unlock(internal->lock); - return KS_STATUS_FAIL; /* we were not able to find a bucket*/ - } -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Insert node: LOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); -#endif - - ks_rwl_write_lock(bucket->lock); - - while (bucket->count == KS_DHT_BUCKETSIZE) { - if (insanity > 3200) assert(insanity < 3200); - - /* first - seek a stale entry to eject */ - if (bucket->expired_count) { - ks_dhtrt_bucket_entry_t* entry = ks_dhtrt_insert_id(bucket, node); - - if (entry != NULL) { -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "insert node: UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); -#endif - ks_rwl_write_unlock(bucket->lock); - ks_rwl_write_unlock(internal->lock); - return KS_STATUS_SUCCESS; - } - } - - if ( !(header->flags & BHF_LEFT) ) { /* only the left handside node can be split */ - ks_log(KS_LOG_DEBUG, "nodeid %s was not inserted\n", ks_dhtrt_printableid(node->nodeid.id, buf)); -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Insert node: UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); -#endif - ks_rwl_write_unlock(bucket->lock); - ks_rwl_write_unlock(internal->lock); - return KS_STATUS_FAIL; - } - - /* bucket must be split */ - /* work out new mask */ - unsigned char newmask[KS_DHT_NODEID_SIZE]; - memcpy(newmask, header->mask, KS_DHT_NODEID_SIZE); - - if (newmask[KS_DHT_NODEID_SIZE-1] == 0) { /* no more bits to shift - is this possible */ - ks_log(KS_LOG_DEBUG,"Nodeid %s was not inserted\n", ks_dhtrt_printableid(node->nodeid.id, buf)); -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Insert node: UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); -#endif - ks_rwl_write_unlock(bucket->lock); - ks_rwl_write_unlock(internal->lock); - return KS_STATUS_FAIL; - } - - /* shift right 1 bit */ - ks_dhtrt_shiftright(newmask); - - /* create the new bucket structures */ - ks_dhtrt_bucket_header_t *newleft = ks_dhtrt_create_bucketheader(table->pool, header, newmask); - - newleft->bucket = ks_dhtrt_create_bucket(table->pool); - newleft->flags = BHF_LEFT; /* flag as left hand side - therefore splitable */ - - ks_dhtrt_bucket_header_t *newright = ks_dhtrt_create_bucketheader(table->pool, header, header->mask); - - newright->right1bit = newleft; - newleft->left1bit = newright; - - ks_dhtrt_split_bucket(header, newleft, newright); - internal->header_count += 2; - ++internal->bucket_count; - - /* ok now we need to try again to see if the bucket has capacity */ - /* which bucket do care about */ - if (ks_dhtrt_ismasked(node->nodeid.id, newleft->mask)) { - bucket = newleft->bucket; -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Insert node: UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->right->mask, buf)); - ks_log(KS_LOG_DEBUG, "Insert node: LOCKING bucket %s\n", ks_dhtrt_printableid(newleft->mask, buf)); -#endif - - ks_rwl_write_lock(bucket->lock); /* lock new bucket */ - ks_rwl_write_unlock(header->right->bucket->lock); /* unlock old bucket */ - header = newleft; - } - else { - bucket = newright->bucket; - /* note: we still hold a lock on the bucket */ - header = newright; - } - ++insanity; - } - - ks_log(KS_LOG_DEBUG, "Inserting nodeid %s\n", ks_dhtrt_printableid(node->nodeid.id, buf)); - ks_log(KS_LOG_DEBUG, " ...into bucket %s\n", buf); - - ks_status_t s = KS_STATUS_FAIL; - - ks_dhtrt_bucket_entry_t* entry = ks_dhtrt_insert_id(bucket, node); - if (entry != NULL) { - s = KS_STATUS_SUCCESS; - /* touch */ - if (flags == KS_DHTRT_CREATE_TOUCH) { - entry->flags = DHTPEER_ACTIVE; - entry->touched = 1; - } - else if (flags == KS_DHTRT_CREATE_PING ) { - ks_dhtrt_ping(internal, entry); - } - } - ks_rwl_write_unlock(internal->lock); -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Insert node: UNLOCKING bucket %s\n", - ks_dhtrt_printableid(header->mask, buf)); -#endif - ks_rwl_write_unlock(bucket->lock); - return s; -} - -KS_DECLARE(ks_dht_node_t *) ks_dhtrt_find_node(ks_dhtrt_routetable_t *table, ks_dht_nodeid_t nodeid) -{ - if (!table || !table->internal) { - return NULL; - } - - ks_dht_node_t* node = NULL; - ks_dhtrt_internal_t* internal = table->internal; - - ks_rwl_read_lock(internal->lock); /* grab read lock */ - - ks_dhtrt_bucket_header_t *header = ks_dhtrt_find_bucketheader(table, nodeid.id); - - if (header != 0) { - - ks_dhtrt_bucket_t *bucket = header->bucket; - - if (bucket != 0) { /* probably a logic error ?*/ - -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - char bufx[51]; - ks_log(KS_LOG_DEBUG, "Find node: read LOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, bufx)); -#endif - - ks_rwl_read_lock(bucket->lock); - node = ks_dhtrt_find_nodeid(bucket, nodeid.id); - - if (node != NULL) { - ks_rwl_read_lock(node->reflock); - } -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Find node: read UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, bufx)); -#endif - ks_rwl_read_unlock(bucket->lock); - } - - } - - ks_rwl_read_unlock(internal->lock); - return node; -} - -KS_DECLARE(ks_status_t) ks_dhtrt_touch_node(ks_dhtrt_routetable_t *table, ks_dht_nodeid_t nodeid) -{ - if (!table || !table->internal) { - return KS_STATUS_FAIL; - } - - ks_status_t s = KS_STATUS_FAIL; - ks_dhtrt_internal_t* internal = table->internal; - - ks_rwl_read_lock(internal->lock); /* grab read lock */ - - ks_dhtrt_bucket_header_t *header = ks_dhtrt_find_bucketheader(table, nodeid.id); - - if (header != 0 && header->bucket != 0) { - ks_rwl_write_lock(header->bucket->lock); -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - char bufx[51]; - ks_log(KS_LOG_DEBUG, "Touch node: write bucket %s\n", ks_dhtrt_printableid(header->mask, bufx)); -#endif - - ks_dhtrt_bucket_entry_t *e = ks_dhtrt_find_bucketentry(header, nodeid.id); - - if (e != 0) { - e->tyme = ks_time_now_sec(); - e->outstanding_pings = 0; - e->touched = 1; - - if (e->flags == DHTPEER_EXPIRED) { - --header->bucket->expired_count; - } - - e->flags = DHTPEER_ACTIVE; - s = KS_STATUS_SUCCESS; - } -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG, "Touch node: UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, bufx)); -#endif - ks_rwl_write_unlock(header->bucket->lock); - } - ks_rwl_read_unlock(internal->lock); /* release read lock */ - return s; -} - -KS_DECLARE(ks_status_t) ks_dhtrt_expire_node(ks_dhtrt_routetable_t *table, ks_dht_nodeid_t nodeid) -{ - if (!table || !table->internal) { - return KS_STATUS_FAIL; - } - - ks_status_t s = KS_STATUS_FAIL; - ks_dhtrt_internal_t *internal = table->internal; - - ks_rwl_read_lock(internal->lock); /* grab read lock */ - ks_dhtrt_bucket_header_t *header = ks_dhtrt_find_bucketheader(table, nodeid.id); - - if (header != 0 && header->bucket != 0) { - ks_rwl_write_lock(header->bucket->lock); - ks_dhtrt_bucket_entry_t *e = ks_dhtrt_find_bucketentry(header, nodeid.id); - - if (e != 0) { - e->flags = DHTPEER_EXPIRED; - s = KS_STATUS_SUCCESS; - } - ks_rwl_write_unlock(header->bucket->lock); - } - ks_rwl_read_unlock(internal->lock); /* release read lock */ - return s; -} - -KS_DECLARE(uint8_t) ks_dhtrt_findclosest_nodes(ks_dhtrt_routetable_t *table, ks_dhtrt_querynodes_t *query) -{ - if (!table || !table->internal) { - return KS_STATUS_FAIL; - query->count = 0; - } - - uint8_t count = 0; - ks_dhtrt_internal_t *internal = table->internal; - - ks_rwl_read_lock(internal->lock); /* grab read lock */ - count = ks_dhtrt_findclosest_locked_nodes(table, query); - ks_rwl_read_unlock(internal->lock); /* release read lock */ - return count; -} - -static -uint8_t ks_dhtrt_findclosest_locked_nodes(ks_dhtrt_routetable_t *table, ks_dhtrt_querynodes_t *query) -{ - char buf[51]; - uint8_t total = 0; - uint8_t cnt; - - if (query->max == 0) return 0; /* sanity checks */ - if (query->max > KS_DHTRT_MAXQUERYSIZE) { /* enforce the maximum */ - query->max = KS_DHTRT_MAXQUERYSIZE; - } - - query->count = 0; - - ks_dhtrt_bucket_header_t *header = ks_dhtrt_find_bucketheader(table, query->nodeid.id); - - ks_log(KS_LOG_DEBUG, "Finding %d closest nodes for nodeid %s\n", - query->max, - ks_dhtrt_printableid(query->nodeid.id, buf)); - ks_log(KS_LOG_DEBUG, " ...starting at mask: %s\n", buf); - - ks_dhtrt_sortedxors_t xort0; - memset(&xort0, 0 , sizeof(xort0)); - - ks_dhtrt_nodeid_t initid; - - memset(initid, 0xff, KS_DHT_NODEID_SIZE); - xort0.bheader = header; - - /* step 1 - look at immediate bucket */ - /* --------------------------------- */ - int max = query->max; - cnt = ks_dhtrt_findclosest_bucketnodes(query->nodeid.id, query->type, query->family, header, &xort0, initid ,max); - total += cnt; - -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG, "Bucket %s yielded %d nodes; total=%d\n", buf, cnt, total); -#endif - - if (total >= query->max || - !header->parent ) { /* is query answered ? */ - return ks_dhtrt_load_query(query, &xort0); - } - - /* step2 - look at sibling */ - /* ----------------------- */ - ks_dhtrt_sortedxors_t xort1; - - xort0.next = &xort1; - memset(&xort1, 0 , sizeof(xort1)); - memcpy(initid, &xort0.hixor, KS_DHT_NODEID_SIZE); - - ks_dhtrt_bucket_header_t *parent = header->parent; - - if (header == parent->left) { - xort1.bheader = header = parent->right; - } else { - if (!parent->left->bucket) { /* left hand might no have a bucket - if so choose left->right */ - xort1.bheader = header = parent->left->right; - } else { - xort1.bheader = header = parent->left; - } - } - - max = query->count - total; - cnt = ks_dhtrt_findclosest_bucketnodes(query->nodeid.id, query->type, query->family, header, &xort1, initid ,max); - total += cnt; - -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG," stage2: sibling bucket header %s yielded %d nodes, total=%d\n", - ks_dhtrt_printableid(header->mask, buf), cnt, total); -#endif - - if (total >= query->max) { /* is query answered ? */ - return ks_dhtrt_load_query(query, &xort0); - } - - /* step3 and beyond ... work left and right until the count is satisfied */ - /* ---------------------------------------------------------------------- */ - memcpy(initid, &xort0.hixor, KS_DHT_NODEID_SIZE); - - unsigned char leftid[KS_DHT_NODEID_SIZE]; - unsigned char rightid[KS_DHT_NODEID_SIZE]; - - memcpy(leftid, xort0.bheader->mask, KS_DHT_NODEID_SIZE); - memcpy(rightid, xort1.bheader->mask, KS_DHT_NODEID_SIZE); - - int insanity = 0; - ks_dhtrt_bucket_header_t *lheader = 0; - ks_dhtrt_bucket_header_t *rheader = 0; - ks_dhtrt_bucket_header_t *last_rheader = 0; - ks_dhtrt_bucket_header_t *last_lheader = 0; - ks_dhtrt_sortedxors_t *prev = &xort1; - ks_dhtrt_sortedxors_t *tofree = 0; - ks_dhtrt_sortedxors_t *xortn; - ks_dhtrt_sortedxors_t *xortn1; - - do { - last_lheader = lheader; - lheader = 0; - last_rheader = rheader; - rheader = 0; - xortn = 0; - xortn1 = 0; - - if (leftid[0] != 0xff) { - - ks_dhtrt_shiftleft(leftid); - - if (last_lheader && last_lheader->left1bit) { - lheader = last_lheader->left1bit = ks_dhtrt_find_relatedbucketheader(last_lheader->left1bit, leftid); - } - else { - lheader = ks_dhtrt_find_bucketheader(table, leftid); - if (last_lheader) { - last_lheader->left1bit = lheader; /* remember so we can take a shortcut next query */ - } - } - - if (lheader) { - xortn = ks_pool_alloc(table->pool, sizeof(ks_dhtrt_sortedxors_t)); - - if (tofree == 0) { - tofree = xortn; - } - - prev->next = xortn; - prev = xortn; - max = query->max - total; - cnt = ks_dhtrt_findclosest_bucketnodes(query->nodeid.id, query->type, query->family, - lheader, xortn, leftid ,max); - total += cnt; -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG," stage3: seaching left bucket header %s yielded %d nodes, total=%d\n", - ks_dhtrt_printableid(lheader->mask, buf), cnt, total); -#endif - } -#ifdef KS_DHT_DEBUGPRINTF_ - else { - ks_log(KS_LOG_DEBUG," stage3: failed to find left header %s\n", - ks_dhtrt_printableid(leftid, buf)); - } -#endif - - } - - if (rightid[KS_DHT_NODEID_SIZE-1] != 0x00) { - - ks_dhtrt_shiftright(rightid); - - if (last_rheader && last_rheader->right1bit) { - rheader = last_rheader->right1bit = ks_dhtrt_find_relatedbucketheader(last_rheader->right1bit, rightid); - } - else { - rheader = ks_dhtrt_find_bucketheader(table, rightid); - if (rheader == last_rheader) { /* did we get the same bucket header returned */ - rheader = 0; /* yes: we are done on the left hand branch */ - } - else { - if (last_rheader) { - last_rheader->left1bit = rheader; /* remember so we can take a shortcut next query */ - } - } - } - - if (rheader) { - xortn1 = ks_pool_alloc(table->pool, sizeof(ks_dhtrt_sortedxors_t)); - - if (tofree == 0) { - tofree = xortn1; - } - - prev->next = xortn1; - prev = xortn1; - max = query->max - total; - cnt = ks_dhtrt_findclosest_bucketnodes(query->nodeid.id, query->type, query->family, - rheader, xortn1, rightid , max); - total += cnt; -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG," stage3: seaching right bucket header %s yielded %d nodes, total=%d\n", - ks_dhtrt_printableid(rheader->mask, buf), cnt, total); -#endif - } -#ifdef KS_DHT_DEBUGPRINTF_ - else { - ks_log(KS_LOG_DEBUG," stage3: failed to find right header %s\n", - ks_dhtrt_printableid(rightid, buf)); - } -#endif - - } - - if (!lheader && !rheader) { - break; - } - - ++insanity; - - if (insanity > 159) { - assert(insanity <= 159); - } - } while (total < query->max); - - - ks_dhtrt_load_query(query, &xort0); - - /* free up the xort structs on heap */ - while (tofree) { - ks_dhtrt_sortedxors_t *x = tofree->next; - - ks_pool_free(table->pool, &tofree); - tofree = x; - } - - return query->count; -} - -KS_DECLARE(ks_status_t) ks_dhtrt_release_node(ks_dht_node_t* node) -{ - assert(node); - return ks_rwl_read_unlock(node->reflock); -} - -KS_DECLARE(ks_status_t) ks_dhtrt_sharelock_node(ks_dht_node_t* node) -{ - assert(node); - return ks_rwl_read_lock(node->reflock); -} - -KS_DECLARE(ks_status_t) ks_dhtrt_release_querynodes(ks_dhtrt_querynodes_t *query) -{ - for(int ix=0; ixcount; ++ix) { - ks_rwl_read_unlock(query->nodes[ix]->reflock); - } - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(void) ks_dhtrt_process_table(ks_dhtrt_routetable_t *table) -{ - /* walk the table and update the status of all known knodes */ - /* anything that is suspect automatically becomes expired */ - - /* inactive for 15 minutes, a node becomes quesionable */ - /* it should be pinged */ - - /* if it has not been 'touched' since the last time */ - /* give it one more try */ - - /* inactive again it is considered inactive */ - /* */ - - char buf[51]; - - if (!table || !table->internal) { - return; - } - - ks_dhtrt_internal_t *internal = table->internal; - int ping_count = 0; - int ping2_count = 0; - - ks_time_t t0 = ks_time_now_sec(); - - if (t0 - internal->last_process_table < internal->next_process_table_delta) { - /*printf("process table: next scan not scheduled\n");*/ - return; - } - - internal->last_process_table = t0; - - ks_log(KS_LOG_DEBUG,"process_table in progress\n"); - - ks_rwl_read_lock(internal->lock); /* grab read lock */ - - ks_dhtrt_bucket_header_t *header = internal->buckets; - ks_dhtrt_bucket_header_t *stack[KS_DHT_NODEID_SIZE * 8]; - int stackix=0; - - while (header) { - stack[stackix++] = header; - - if (header->bucket) { - - ks_dhtrt_bucket_t *b = header->bucket; - - if (ks_rwl_try_write_lock(b->lock) == KS_STATUS_SUCCESS) { - -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - ks_log(KS_LOG_DEBUG,"process_table: LOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); -#endif - - - if (b->count == 0) { - - if (t0 - b->findtyme >= (ks_time_t)KS_DHTRT_EXPIREDTIME) { /* bucket has been empty for a while */ - - ks_dht_nodeid_t targetid; - - if (header->right1bit) { - ks_dhtrt_midmask(header->mask, header->right1bit->mask, targetid.id); - } - else { - ks_dhtrt_nodeid_t rightid; - memcpy(rightid, header->mask, KS_DHT_NODEID_SIZE); - ks_dhtrt_shiftright(rightid); - ks_dhtrt_midmask(header->mask, rightid, targetid.id); - } - - ks_dhtrt_find(table, internal, &targetid); - b->findtyme = t0; - } - } - else { - for (int ix=0; ixentries[ix]; - - if (e->inuse == 1) { - - ks_time_t tdiff = t0 - e->tyme; - - if (e->gptr->type != KS_DHT_LOCAL) { /* 'local' nodes do not get expired */ - - /* more than n pings outstanding? */ - - if (e->flags == DHTPEER_DUBIOUS) { - continue; /* nothin' to see here */ - } - - /* refresh empty buckets */ - if ( e->flags != DHTPEER_EXPIRED && - tdiff >= KS_DHTRT_EXPIREDTIME && /* beyond expired time */ - e->outstanding_pings >= KS_DHTRT_MAXPING ) { /* has been retried */ - ks_log(KS_LOG_DEBUG,"process_table: expiring node %s\n", - ks_dhtrt_printableid(e->gptr->nodeid.id, buf)); - e->flags = DHTPEER_EXPIRED; - ++b->expired_count; - e->outstanding_pings = 0; /* extinguish all hope: do not retry again */ - continue; - } - - /* re ping in-doubt nodes */ - if ( e->outstanding_pings > 0) { - ks_time_t tping = t0 - e->ping_tyme; /* time since we last pinged */ - - if (e->outstanding_pings == KS_DHTRT_MAXPING - 1) { /* final ping */ - ks_dhtrt_ping(internal, e); - e->ping_tyme = t0; - ++ping2_count; - } - else if (tping >= KS_DHTRT_PROCESSTABLE_SHORTINTERVAL120) { - ks_dhtrt_ping(internal, e); - e->ping_tyme = t0; - ++ping_count; - } - continue; - } - - /* look for newly expired nodes */ - if (tdiff > KS_DHTRT_EXPIREDTIME) { - e->flags = DHTPEER_DUBIOUS; /* mark as dubious */ - ks_dhtrt_ping(internal, e); /* final effort to activate */ - e->ping_tyme = t0; - continue; - } - - if (tdiff > KS_DHTRT_INACTIVETIME) { /* inactive for suspicious length */ - ks_dhtrt_ping(internal, e); /* kick */ - e->ping_tyme = t0; - ++ping_count; - continue; - } - - } /* end if not local */ - - } /* end if e->inuse */ - - } /* end for each bucket_entry */ - } /* if bucket->count == 0 .... else */ - -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - char buf[100]; - ks_log(KS_LOG_DEBUG,"process_table: UNLOCKING bucket %s\n", ks_dhtrt_printableid(header->mask, buf)); -#endif - - ks_rwl_write_unlock(b->lock); - - } /* end of if trywrite_lock successful */ - else { -#ifdef KS_DHT_DEBUGPRINTF_ - char buf1[100]; - ks_log(KS_LOG_DEBUG,"process_table: unble to LOCK bucket %s\n", ks_dhtrt_printableid(header->mask, buf1)); -#endif - } - } - - header = header->left; - - if (header == 0 && stackix > 1) { - stackix -= 2; - header = stack[stackix]; - header = header->right; - } - } - ks_rwl_read_unlock(internal->lock); /* release read lock */ - - ks_dhtrt_process_deleted(table, 0); - - if (ping2_count > 0) { - internal->next_process_table_delta = KS_DHTRT_PROCESSTABLE_SHORTINTERVAL60; - } - if (ping_count > 0) { - internal->next_process_table_delta = KS_DHTRT_PROCESSTABLE_SHORTINTERVAL120; - } - else { - internal->next_process_table_delta = KS_DHTRT_PROCESSTABLE_INTERVAL; - } - ks_log(KS_LOG_DEBUG,"process_table complete\n"); - - return; -} - -void ks_dhtrt_process_deleted(ks_dhtrt_routetable_t *table, int8_t all) -{ - ks_dhtrt_internal_t* internal = table->internal; - ks_mutex_lock(internal->deleted_node_lock); - - ks_dhtrt_deletednode_t *deleted = internal->deleted_node; - ks_dhtrt_deletednode_t *prev = NULL, *temp=NULL; - -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG, "ALLOC process_deleted entry: internal->deleted_count %d\n", internal->deleted_count); -#endif - - - /* reclaim excess memory */ - uint32_t threshold = KS_DHTRT_RECYCLE_NODE_THRESHOLD; - - if (all) { - threshold = 0; - } - - while(internal->deleted_count > threshold && deleted) { - ks_dht_node_t* node = deleted->node; - -#ifdef KS_DHT_DEBUGPRINTFX_ - ks_log(KS_LOG_DEBUG, "ALLOC process_deleted : try write lock\n"); -#endif - - if (ks_rwl_try_write_lock(node->reflock) == KS_STATUS_SUCCESS) { - ks_rwl_destroy(&(node->reflock)); - ks_pool_free(table->pool, &node); - temp = deleted; - deleted = deleted->next; - ks_pool_free(table->pool, &temp); - --internal->deleted_count; -#ifdef KS_DHT_DEBUGPRINTFX__ - ks_log(KS_LOG_DEBUG, "ALLOC process_deleted: internal->deleted_count reduced to %d\n", internal->deleted_count); -#endif - if (prev != NULL) { - prev->next = deleted; - } - else { - internal->deleted_node = deleted; - } - - } - else { -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG, "ALLOC process_deleted : try write lock failed\n"); -#endif - prev = deleted; - deleted = prev->next; - } - } - -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG, "ALLOC process_deleted exit: internal->deleted_count %d\n", internal->deleted_count); -#endif - - ks_mutex_unlock(internal->deleted_node_lock); -} - - -KS_DECLARE(void) ks_dhtrt_dump(ks_dhtrt_routetable_t *table, int level) { - /* dump buffer headers */ - char buffer[100]; - memset(buffer, 0, 100); - ks_dhtrt_internal_t *internal = table->internal; - ks_dhtrt_bucket_header_t *header = internal->buckets; - ks_dhtrt_bucket_header_t *stack[KS_DHT_NODEID_SIZE * 8]; - int stackix = 0; - - ks_rwl_read_lock(internal->lock); /* grab read lock */ - while (header) { - stack[stackix++] = header; - /* walk and report left handsize */ - memset(buffer, 0, 100); - ks_log(KS_LOG_DEBUG, "bucket header: [%s]\n", ks_dhtrt_printableid(header->mask, buffer) ); - - if (header->bucket) { - ks_dhtrt_bucket_t *b = header->bucket; - ks_log(KS_LOG_DEBUG, " bucket holds %d entries\n", b->count); - - if (b->count > 0 && level == 7) { - ks_log(KS_LOG_DEBUG, " --------------------------\n"); - - for (int ix=0; ixentries[ix].inuse == 1) { - ks_dhtrt_printableid(b->entries[ix].gptr->nodeid.id, buffer); - ks_dht_node_t *n = b->entries[ix].gptr; - ks_log(KS_LOG_DEBUG, " slot %d: flags:%d %d type:%d family:%d %s\n", ix, - b->entries[ix].flags, - b->entries[ix].outstanding_pings, - n->type, - n->addr.family, - buffer); - } - else { - ks_log(KS_LOG_DEBUG, " slot %d: \n", ix); - } - } - - ks_log(KS_LOG_DEBUG, " --------------------------\n\n"); - } - - } - - header = header->left; - - if (header == 0 && stackix > 1) { - stackix -= 2; - header = stack[stackix]; - header = header->right; - } - } - ks_rwl_read_unlock(internal->lock); /* release read lock */ - return; -} - -/* - internal functions -*/ - -static -ks_dhtrt_bucket_header_t *ks_dhtrt_create_bucketheader(ks_pool_t *pool, ks_dhtrt_bucket_header_t *parent, uint8_t *mask) -{ - ks_dhtrt_bucket_header_t *header = ks_pool_alloc(pool, sizeof(ks_dhtrt_bucket_header_t)); - - memcpy(header->mask, mask, sizeof(header->mask)); - header->parent = parent; - -#ifdef KS_DHT_DEBUGPRINTF_ - char buffer[100]; - ks_log(KS_LOG_DEBUG, "creating bucket header for mask: %s\n", ks_dhtrt_printableid(mask, buffer)); - if (parent) { - ks_log(KS_LOG_DEBUG, " ... from parent mask: %s\n", ks_dhtrt_printableid(parent->mask, buffer)); - } -#endif - return header; -} - -static -ks_dhtrt_bucket_t *ks_dhtrt_create_bucket(ks_pool_t *pool) -{ - ks_dhtrt_bucket_t *bucket = ks_pool_alloc(pool, sizeof(ks_dhtrt_bucket_t)); - ks_rwl_create(&bucket->lock, pool); - return bucket; -} - -static -ks_dhtrt_bucket_header_t *ks_dhtrt_find_bucketheader(ks_dhtrt_routetable_t *table, ks_dhtrt_nodeid_t id) -{ - /* find the right bucket. - if a bucket header has a bucket, it does not children - so it must be the bucket to use - */ - ks_dhtrt_internal_t *internal = table->internal; - ks_dhtrt_bucket_header_t *header = internal->buckets; - - while (header) { - if ( header->bucket ) { - return header; - } - - /* left hand side is more restrictive (closer) so should be tried first */ - if (header->left != 0 && (ks_dhtrt_ismasked(id, header->left->mask))) { - header = header->left; - } else { - header = header->right; - } - } - - return NULL; -} - -static -ks_dhtrt_bucket_header_t *ks_dhtrt_find_relatedbucketheader(ks_dhtrt_bucket_header_t *header, ks_dhtrt_nodeid_t id) -{ - /* - using the passed bucket header as a starting point find the right bucket. - This is a shortcut used in query to shorten the search path for queries extending beyond a single bucket. - */ - - while (header) { - if ( header->bucket ) { - return header; - } - - /* left hand side is more restrictive (closer) so should be tried first */ - if (header->left != 0 && (ks_dhtrt_ismasked(id, header->left->mask))) { - header = header->left; - } else { - header = header->right; - } - } - return NULL; -} - - - -static -ks_dhtrt_bucket_entry_t *ks_dhtrt_find_bucketentry(ks_dhtrt_bucket_header_t *header, ks_dhtrt_nodeid_t nodeid) -{ - ks_dhtrt_bucket_t *bucket = header->bucket; - - if (bucket == 0) return NULL; - - for (int ix=0; ixentries[ix].inuse == 1 && - (!memcmp(nodeid, bucket->entries[ix].gptr->nodeid.id, KS_DHT_NODEID_SIZE)) ) { - return &(bucket->entries[ix]); - } - } - - return NULL; -} - - -static -void ks_dhtrt_split_bucket(ks_dhtrt_bucket_header_t *original, - ks_dhtrt_bucket_header_t *left, - ks_dhtrt_bucket_header_t *right) -{ - /* so split the bucket in two based on the masks in the new header */ - /* the existing bucket - with the remaining ids will be taken by the right hand side */ - - ks_dhtrt_bucket_t *source = original->bucket; - ks_dhtrt_bucket_t *dest = left->bucket; - - int lix = 0; - int rix = 0; - - for ( ; rixentries[rix].gptr->nodeid.id, left->mask)) { - - /* move it to the left */ - memcpy(&dest->entries[lix], &source->entries[rix], sizeof(ks_dhtrt_bucket_entry_t)); - ++lix; - ++dest->count; - - /* now remove it from the original bucket */ - source->entries[rix].inuse = 0; - --source->count; - } - } - - /* give original bucket to the new left hand side header */ - right->bucket = source; - original->bucket = 0; - original->left = left; - original->right = right; -#ifdef KS_DHT_DEBUGPRINTF_ - char buffer[100]; - ks_log(KS_LOG_DEBUG, "\nsplitting bucket orginal: %s\n", ks_dhtrt_printableid(original->mask, buffer)); - ks_log(KS_LOG_DEBUG, " into (left) mask: %s size: %d\n", ks_dhtrt_printableid(left->mask, buffer), left->bucket->count); - ks_log(KS_LOG_DEBUG, " and (right) mask: %s size: %d\n", ks_dhtrt_printableid(right->mask, buffer), right->bucket->count); -#endif - return; -} - - -/* - * buckets are implemented as static array - * There does not seem to be any advantage in sorting/tree structures in terms of xor math - * so at least the static array does away with the need for locking. - */ -static -ks_dhtrt_bucket_entry_t* ks_dhtrt_insert_id(ks_dhtrt_bucket_t *bucket, ks_dht_node_t *node) -{ - /* sanity checks */ - if (!bucket || bucket->count > KS_DHT_BUCKETSIZE) { - assert(0); - } - - uint8_t free = KS_DHT_BUCKETSIZE; - uint8_t expiredix = KS_DHT_BUCKETSIZE; - - /* find free .. but also check that it is not already here! */ - uint8_t ix = 0; - - for (; ixentries[ix].inuse == 0) { - - if (free == KS_DHT_BUCKETSIZE) { - free = ix; /* use this one */ - } - - } - else if (free == KS_DHT_BUCKETSIZE && bucket->entries[ix].flags == DHTPEER_EXPIRED) { - expiredix = ix; - } - - else if (!memcmp(bucket->entries[ix].gptr->nodeid.id, node->nodeid.id, KS_DHT_NODEID_SIZE)) { -#ifdef KS_DHT_DEBUGPRINTF_ - char buffer[100]; - ks_log(KS_LOG_DEBUG, "duplicate peer %s found at %d\n", ks_dhtrt_printableid(node->nodeid.id, buffer), ix); -#endif - bucket->entries[ix].tyme = ks_time_now_sec(); - return &bucket->entries[ix]; /* already exists : leave flags unchanged */ - } - } - - if (free == KS_DHT_BUCKETSIZE && expiredixexpired_count; - } - - if ( freeentries[free].inuse = 1; - bucket->entries[free].gptr = node; - bucket->entries[free].tyme = ks_time_now_sec(); - bucket->entries[free].flags = DHTPEER_DUBIOUS; - - if (free != expiredix) { /* are we are taking a free slot rather than replacing an expired node? */ - ++bucket->count; /* yes: increment total count */ - } - - memcpy(bucket->entries[free].gptr->nodeid.id, node->nodeid.id, KS_DHT_NODEID_SIZE); -#ifdef KS_DHT_DEBUGPRINTF_ - char buffer[100]; - ks_log(KS_LOG_DEBUG, "Inserting node %s at %d\n", ks_dhtrt_printableid(node->nodeid.id, buffer), free); -#endif - return &bucket->entries[free]; - } - - return NULL; -} - -static -ks_dht_node_t *ks_dhtrt_find_nodeid(ks_dhtrt_bucket_t *bucket, ks_dhtrt_nodeid_t id) -{ -#ifdef KS_DHT_DEBUGPRINTF_ - char buffer[100]; - ks_log(KS_LOG_DEBUG, "Find nodeid for: %s\n", ks_dhtrt_printableid(id, buffer)); -#endif - - - for (int ix=0; ixentries[ix].inuse == 1 && bucket->entries[ix].flags == DHTPEER_ACTIVE ) { - ks_log(KS_LOG_DEBUG, "bucket->entries[%d].id = %s inuse=%x\n", ix, - ks_dhtrt_printableid(bucket->entries[ix].id, bufferx), - bucket->entries[ix].inuse ); - } -#endif - if ( bucket->entries[ix].inuse == 1 && - bucket->entries[ix].flags == DHTPEER_ACTIVE && - (!memcmp(id, bucket->entries[ix].gptr->nodeid.id, KS_DHT_NODEID_SIZE)) ) { - return bucket->entries[ix].gptr; - } - } - return NULL; -} - -static -ks_status_t ks_dhtrt_delete_id(ks_dhtrt_bucket_t *bucket, ks_dhtrt_nodeid_t id) -{ -#ifdef KS_DHT_DEBUGPRINTF_ - char buffer[100]; - ks_log(KS_LOG_DEBUG, "deleting node for: %s\n", ks_dhtrt_printableid(id, buffer)); -#endif - - for (int ix=0; ixentries[%d].id = %s inuse=%c\n", ix, - ks_dhtrt_printableid(bucket->entries[ix].gptr->nodeid.id, bufferx), - bucket->entries[ix].inuse ); -#endif - if ( bucket->entries[ix].inuse == 1 && - (!memcmp(id, bucket->entries[ix].gptr->nodeid.id, KS_DHT_NODEID_SIZE)) ) { - bucket->entries[ix].inuse = 0; - bucket->entries[ix].gptr = 0; - bucket->entries[ix].flags = 0; - --bucket->count; - return KS_STATUS_SUCCESS; - } - } - return KS_STATUS_FAIL; -} - - -static -uint8_t ks_dhtrt_findclosest_bucketnodes(ks_dhtrt_nodeid_t id, - enum ks_dht_nodetype_t type, - enum ks_afflags_t family, - ks_dhtrt_bucket_header_t *header, - ks_dhtrt_sortedxors_t *xors, - unsigned char *hixor, /*todo: remove */ - unsigned int max) { - - uint8_t count = 0; /* count of nodes added this time */ - xors->startix = KS_DHT_BUCKETSIZE; - xors->count = 0; - xors->bheader = header; - unsigned char xorvalue[KS_DHT_NODEID_SIZE]; - - /* just ugh! - there must be a better way to do this */ - /* walk the entire bucket calculating the xor value on the way */ - /* add valid & relevant entries to the xor values */ - ks_dhtrt_bucket_t *bucket = header->bucket; - - if (bucket == 0) { /* sanity */ -#ifdef KS_DHT_DEBUGPRINTF_ - char buf[100]; - ks_log(KS_LOG_DEBUG, "closestbucketnodes: intermediate tree node found %s\n", - ks_dhtrt_printableid(header->mask, buf)); -#endif - - } - - ks_rwl_read_lock(bucket->lock); /* get a read lock : released in load_query when the results are copied */ -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - char buf[100]; - ks_log(KS_LOG_DEBUG, "closestbucketnodes: LOCKING bucket %s\n", - ks_dhtrt_printableid(header->mask, buf)); -#endif - - - for (uint8_t ix=0; ixentries[ix].inuse == 1 && /* in use */ - bucket->entries[ix].flags == DHTPEER_ACTIVE && /* not dubious or expired */ - (family == ifboth || bucket->entries[ix].gptr->addr.family == family) && /* match if family */ - (bucket->entries[ix].gptr->type & type) ) { /* match type */ - - /* calculate xor value */ - ks_dhtrt_xor(bucket->entries[ix].gptr->nodeid.id, id, xorvalue ); - - /* do we need to hold this one */ - if ( count < max || /* yes: we have not filled the quota yet */ - (memcmp(xorvalue, hixor, KS_DHT_NODEID_SIZE) < 0)) { /* or is closer node than one already selected */ - - /* now sort the new xorvalue into the results structure */ - /* this now becomes worst case O(n*2) logic - is there a better way */ - /* in practice the bucket size is fixed so actual behavior is proably 0(logn) */ - unsigned int xorix = xors->startix; /* start of ordered list */ - unsigned int prev_xorix = KS_DHT_BUCKETSIZE; - - for (int ix2=0; ix2xort[xorix].xor, KS_DHT_NODEID_SIZE) > 0) { - break; /* insert before xorix, after prev_xoris */ - } - - prev_xorix = xorix; - xorix = xors->xort[xorix].nextix; - } - - /* insert point found - count -> array slot to added newly identified node - insert_point -> the array slot before which we need to insert the newly identified node - */ - memcpy(xors->xort[count].xor, xorvalue, KS_DHT_NODEID_SIZE); - xors->xort[count].ix = ix; - - xors->xort[count].nextix = xorix; /* correct forward chain */ - - if (prev_xorix < KS_DHT_BUCKETSIZE) { /* correct backward chain */ - xors->xort[prev_xorix].nextix = count; - } else { - xors->startix = count; - } - ++count; - } - } - } - - xors->count = count; - return count; /* return count of added nodes */ -} - -static -uint8_t ks_dhtrt_load_query(ks_dhtrt_querynodes_t *query, ks_dhtrt_sortedxors_t *xort) -{ - ks_dhtrt_sortedxors_t *current = xort; - uint8_t loaded = 0; - - while (current) { -#ifdef KS_DHT_DEBUGPRINTF_ - char buf[100]; - ks_log(KS_LOG_DEBUG, " loadquery from bucket %s count %d\n", - ks_dhtrt_printableid(current->bheader->mask,buf), current->count); -#endif - int xorix = current->startix; - - for (uint8_t ix = 0; - ix< current->count && loaded < query->max && xorix != KS_DHT_BUCKETSIZE; - ++ix ) { - unsigned int z = current->xort[xorix].ix; - query->nodes[ix] = current->bheader->bucket->entries[z].gptr; - xorix = current->xort[xorix].nextix; - ++loaded; - } - -#ifdef KS_DHT_DEBUGLOCKPRINTF_ - char buf1[100]; - ks_log(KS_LOG_DEBUG, "load_query: UNLOCKING bucket %s\n", - ks_dhtrt_printableid(current->bheader->mask, buf1)); -#endif - ks_rwl_read_unlock(current->bheader->bucket->lock); /* release the read lock from findclosest_bucketnodes */ - - if (loaded >= query->max) break; - current = current->next; - } - query->count = loaded; - - return loaded; -} - -void ks_dhtrt_queue_node_fordelete(ks_dhtrt_routetable_t* table, ks_dht_node_t* node) -{ - ks_dhtrt_internal_t* internal = table->internal; - ks_mutex_lock(internal->deleted_node_lock); - ks_dhtrt_deletednode_t* deleted = internal->free_node_ex; /* grab a free stub */ - - if (deleted) { - internal->free_node_ex = deleted->next; - } - else { - deleted = ks_pool_alloc(table->pool, sizeof(ks_dhtrt_deletednode_t)); - } - - deleted->node = node; - deleted->next = internal->deleted_node; - internal->deleted_node = deleted; /* add to deleted queue */ - ++internal->deleted_count; -#ifdef KS_DHT_DEBUGPRINTF_ - ks_log(KS_LOG_DEBUG, "ALLOC: Queue for delete %d\n", internal->deleted_count); -#endif - ks_mutex_unlock(internal->deleted_node_lock); -} - -ks_dht_node_t* ks_dhtrt_make_node(ks_dhtrt_routetable_t* table) -{ - ks_dht_node_t *node = NULL; - ks_dhtrt_internal_t *internal = table->internal; - ks_mutex_lock(internal->deleted_node_lock); - - /* to to reuse a deleted node */ - if (internal->deleted_count) { - ks_dhtrt_deletednode_t *deleted = internal->deleted_node; - node = deleted->node; /* take the node */ - memset(node, 0, sizeof(ks_dht_node_t)); - deleted->node = 0; /* avoid accidents */ - internal->deleted_node = deleted->next; - deleted->next = internal->free_node_ex; /* save the stub for reuse */ - --internal->deleted_count; -#ifdef KS_DHT_DEBUGPRINTFX_ - ks_log(KS_LOG_DEBUG, "ALLOC: Reusing a node struct %d\n", internal->deleted_count); -#endif - } - ks_mutex_unlock(internal->deleted_node_lock); - - if (!node) { - node = ks_pool_alloc(table->pool, sizeof(ks_dht_node_t)); - } - - return node; -} - -void ks_dhtrt_ping(ks_dhtrt_internal_t *internal, ks_dhtrt_bucket_entry_t *entry) { - ++entry->outstanding_pings; - -#ifdef KS_DHT_DEBUGPRINTF_ - char buf[100]; - ks_log(KS_LOG_DEBUG, "Ping queued for nodeid %s count %d\n", - ks_dhtrt_printableid(entry->gptr->nodeid.id,buf), entry->outstanding_pings); - /*printf("ping: %s\n", buf); fflush(stdout);*/ -#endif - ks_dht_node_t* node = entry->gptr; - ks_log(KS_LOG_DEBUG, "Node addr %s %d\n", node->addr.host, node->addr.port); - ks_dht_ping(internal->dht, &node->addr, NULL, NULL); - - return; -} - -static -void ks_dhtrt_find(ks_dhtrt_routetable_t *table, ks_dhtrt_internal_t *internal, ks_dht_nodeid_t *target) { - - char buf[100]; - ks_log(KS_LOG_DEBUG, "Find queued for target %s\n", ks_dhtrt_printableid(target->id, buf)); - ks_dht_search(internal->dht, NULL, NULL, table, target); - return; -} - -/* - strictly for shifting the bucketheader mask - so format must be a right filled mask (hex: ..ffffffff) -*/ -static -void ks_dhtrt_shiftright(uint8_t *id) -{ - unsigned char b0 = 0; - unsigned char b1 = 0; - - for (int i = KS_DHT_NODEID_SIZE-1; i >= 0; --i) { - if (id[i] == 0) break; /* beyond mask- we are done */ - b1 = id[i] & 0x01; - id[i] >>= 1; - if (i != (KS_DHT_NODEID_SIZE-1)) { - id[i+1] |= (b0 << 7); - } - b0 = b1; - } - return; -} - -static -void ks_dhtrt_shiftleft(uint8_t *id) { - - for (int i = KS_DHT_NODEID_SIZE-1; i >= 0; --i) { - if (id[i] == 0xff) continue; - id[i] <<= 1; - id[i] |= 0x01; - break; - } - return; -} - -static -void ks_dhtrt_midmask(uint8_t *leftid, uint8_t *rightid, uint8_t *midpt) { - - uint8_t i = 0; - - memset(midpt, 0, sizeof KS_DHT_NODEID_SIZE); - - for ( ; i < KS_DHT_NODEID_SIZE; ++i) { - - if (leftid[i] == 0 && rightid[i] == 0) { - continue; - } - else if (leftid[i] == 0 || rightid[i] == 0) { - midpt[i] = leftid[i] | rightid[i]; - continue; - } - else { - if (leftid[i] == rightid[i]) { - midpt[i] = leftid[i] >> 1; - i++; - } - else { - uint16_t x = leftid[i] + rightid[i]; - x >>= 1; - midpt[i++] = (uint8_t)x; - } - break; - } - } - - if (i == KS_DHT_NODEID_SIZE) { - return; - } - - if ( i < KS_DHT_NODEID_SIZE ) { - memcpy(&midpt[i], &rightid[i], KS_DHT_NODEID_SIZE-i); - } - - return; -} - -/* create an xor value from two ids */ -static void ks_dhtrt_xor(const uint8_t *id1, const uint8_t *id2, uint8_t *xor) -{ - for (int i = 0; i < KS_DHT_NODEID_SIZE; ++i) { - if (id1[i] == id2[i]) { - xor[i] = 0; - } - xor[i] = id1[i] ^ id2[i]; - } - return; -} - -/* is id masked by mask 1 => yes, 0=> no */ -static int ks_dhtrt_ismasked(const uint8_t *id, const unsigned char *mask) -{ - for (int i = 0; i < KS_DHT_NODEID_SIZE; ++i) { - if (mask[i] == 0 && id[i] != 0) return 0; - else if (mask[i] == 0xff) return 1; - else if (id[i] > mask[i]) return 0; - } - return 1; -} - -static char *ks_dhtrt_printableid(uint8_t *id, char *buffer) -{ - char *t = buffer; - memset(buffer, 0, KS_DHT_NODEID_SIZE*2); - for (int i = 0; i < KS_DHT_NODEID_SIZE; ++i, buffer+=2) { - sprintf(buffer, "%02x", id[i]); - } - return t; -} - - -/* - * - * serialization and deserialization - * --------------------------------- -*/ - -typedef struct ks_dhtrt_serialized_bucket_s -{ - uint16_t count; - char eye[4]; - ks_dhtrt_nodeid_t id; -} ks_dhtrt_serialized_bucket_t; - -typedef struct ks_dhtrt_serialized_routetable_s -{ - uint32_t size; - uint8_t version; - uint8_t count; - char eye[4]; -} ks_dhtrt_serialized_routetable_t; - -#define DHTRT_SERIALIZATION_VERSION 1 - -static void ks_dhtrt_serialize_node(ks_dht_node_t *source, ks_dht_node_t *dest) -{ - memcpy(dest, source, sizeof(ks_dht_node_t)); - memset(&dest->table, 0, sizeof(void*)); - memset(&dest->reflock, 0, sizeof(void*)); -} - -static void ks_dhtrt_serialize_bucket(ks_dhtrt_routetable_t *table, - ks_dhtrt_serialized_routetable_t *stable, - ks_dhtrt_bucket_header_t* header, - unsigned char* buffer) -{ - uint8_t tzero = 0; - ks_dhtrt_serialized_bucket_t *s = (ks_dhtrt_serialized_bucket_t*)buffer; - - memcpy(s->eye, "HEAD", 4); - memcpy(s->id, header->mask, KS_DHT_NODEID_SIZE); - buffer += sizeof(ks_dhtrt_serialized_bucket_t); - stable->size += sizeof(ks_dhtrt_serialized_bucket_t); - - if (header->bucket != 0) { - ks_dhtrt_bucket_t* bucket = header->bucket; - - memcpy(&s->count, &bucket->count, sizeof(uint8_t)); - - for (int i=0; i< KS_DHT_BUCKETSIZE; ++i) { - if (bucket->entries[i].inuse == 1) { - ks_dhtrt_serialize_node(bucket->entries[i].gptr, (ks_dht_node_t*)buffer); - buffer += sizeof(ks_dht_node_t); - stable->size += sizeof(ks_dht_node_t); - } - } - } - else { - memcpy(&s->count, &tzero, sizeof(uint8_t)); - } -} - -static void ks_dhtrt_serialize_table(ks_dhtrt_routetable_t *table, - ks_dhtrt_serialized_routetable_t *stable, - unsigned char *buffer) -{ - ks_dhtrt_bucket_header_t *stack[KS_DHT_NODEID_SIZE * 8]; - int stackix=0; - - ks_dhtrt_internal_t *internal = table->internal; - ks_dhtrt_bucket_header_t *header = internal->buckets; - - while (header) { - stack[stackix++] = header; - - ++stable->count; - - ks_dhtrt_serialize_bucket(table, stable, header, buffer); - buffer = (unsigned char*)stable + stable->size; - - header = header->left; - - if (header == 0 && stackix > 1) { - stackix -= 2; - header = stack[stackix]; - header = header->right; - } - } - return; -} - -KS_DECLARE(uint32_t) ks_dhtrt_serialize(ks_dhtrt_routetable_t *table, void **ptr) -{ - ks_dhtrt_internal_t *internal = table->internal; - ks_rwl_write_lock(internal->lock); /* grab write lock */ - - uint32_t buffer_size = 3200 * sizeof(ks_dht_node_t); - buffer_size += internal->header_count * sizeof(ks_dhtrt_serialized_bucket_t); - buffer_size += sizeof(ks_dhtrt_serialized_routetable_t); - unsigned char *buffer = (*ptr) = ks_pool_alloc(table->pool, buffer_size); - - ks_dhtrt_serialized_routetable_t *stable = (ks_dhtrt_serialized_routetable_t*)buffer; - stable->size = sizeof(ks_dhtrt_serialized_routetable_t); - stable->version = DHTRT_SERIALIZATION_VERSION; - memcpy(stable->eye, "DHRT", 4); - - buffer += sizeof(ks_dhtrt_serialized_routetable_t); - - ks_dhtrt_serialize_table(table, stable, buffer); - ks_rwl_write_unlock(internal->lock); /* write unlock */ - return stable->size; -} - - -static void ks_dhtrt_deserialize_node(ks_dhtrt_routetable_t *table, - ks_dht_node_t *source, - ks_dht_node_t *dest) -{ - memcpy(dest, source, sizeof(ks_dht_node_t)); - dest->table = table; - ks_rwl_create(&dest->reflock, table->pool); -} - - -KS_DECLARE(ks_status_t) ks_dhtrt_deserialize(ks_dhtrt_routetable_t *table, void* buffer) -{ - ks_dhtrt_internal_t *internal = table->internal; - ks_rwl_write_lock(internal->lock); /* grab write lock */ - unsigned char *ptr = (unsigned char*)buffer; - - ks_dhtrt_serialized_routetable_t *stable = (ks_dhtrt_serialized_routetable_t*)buffer; - ptr += sizeof(ks_dhtrt_serialized_routetable_t); - - /* unpack and chain the buckets */ - for (int i=0; icount; ++i) { - - ks_dhtrt_serialized_bucket_t *s = (ks_dhtrt_serialized_bucket_t*)ptr; - - if (memcmp(s->eye, "HEAD", 4)) { - assert(0); - ks_rwl_write_unlock(internal->lock); /* write unlock */ - return KS_STATUS_FAIL; - } - - ptr += sizeof(ks_dhtrt_serialized_bucket_t); - - /* currently adding the nodes individually - * need a better way to do this that is compatible with the pending - * changes for supernode support - */ - - char buf[51]; - ks_log(KS_LOG_DEBUG, "deserialize bucket [%s] count %d\n", ks_dhtrt_printableid(s->id, buf), s->count); - - int mid = s->count >>1; - ks_dht_node_t *fnode = NULL; - ks_dht_node_t *node = NULL; - - for(int i0=0; i0count; ++i0) { - /* recreate the node */ - ks_dht_node_t *node = ks_pool_alloc(table->pool, sizeof(ks_dht_node_t)); - if (i0 == mid) fnode = node; - ks_dhtrt_deserialize_node(table, (ks_dht_node_t*)ptr, node); - ptr += sizeof(ks_dht_node_t); - ks_dhtrt_insert_node(table, node, 0); - } - - /* - * now the bucket is complete - now trigger a find. - * This staggers the series of finds. We only do this for populated tables here. - * Once the table is loaded, process_table will as normal start the ping/find process to - * update and populate the table. - */ - - if (s->count > 0) { - if (fnode) { - ks_dhtrt_find(table, internal, &fnode->nodeid); - } - else if (node) { - ks_dhtrt_find(table, internal, &node->nodeid); - } - } - } - - ks_rwl_write_unlock(internal->lock); /* write unlock */ - return KS_STATUS_SUCCESS; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ - diff --git a/libs/libblade/src/dht/ks_dht_datagram.c b/libs/libblade/src/dht/ks_dht_datagram.c deleted file mode 100644 index fe98cffc3c..0000000000 --- a/libs/libblade/src/dht/ks_dht_datagram.c +++ /dev/null @@ -1,60 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" -#include "sodium.h" - -KS_DECLARE(ks_status_t) ks_dht_datagram_create(ks_dht_datagram_t **datagram, - ks_pool_t *pool, - ks_dht_t *dht, - ks_dht_endpoint_t *endpoint, - const ks_sockaddr_t *raddr) -{ - ks_dht_datagram_t *dg; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(datagram); - ks_assert(pool); - ks_assert(dht); - ks_assert(endpoint); - ks_assert(raddr); - ks_assert(raddr->family == AF_INET || raddr->family == AF_INET6); - - *datagram = dg = ks_pool_alloc(pool, sizeof(ks_dht_datagram_t)); - ks_assert(dg); - - dg->pool = pool; - dg->dht = dht; - dg->endpoint = endpoint; - dg->raddr = *raddr; - - memcpy(dg->buffer, dht->recv_buffer, dht->recv_buffer_length); - dg->buffer_length = dht->recv_buffer_length; - - // done: - if (ret != KS_STATUS_SUCCESS) { - ks_dht_datagram_destroy(datagram); - } - return ret; -} - -KS_DECLARE(void) ks_dht_datagram_destroy(ks_dht_datagram_t **datagram) -{ - ks_dht_datagram_t *dg; - - ks_assert(datagram); - ks_assert(*datagram); - - dg = *datagram; - - ks_pool_free(dg->pool, datagram); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_distribute.c b/libs/libblade/src/dht/ks_dht_distribute.c deleted file mode 100644 index 24669ebfb8..0000000000 --- a/libs/libblade/src/dht/ks_dht_distribute.c +++ /dev/null @@ -1,65 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" -#include "sodium.h" - -KS_DECLARE(ks_status_t) ks_dht_distribute_create(ks_dht_distribute_t **distribute, - ks_pool_t *pool, - ks_dht_storageitem_callback_t callback, - void *data, - int64_t cas, - ks_dht_storageitem_t *item) -{ - ks_dht_distribute_t *d; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(distribute); - ks_assert(pool); - ks_assert(cas >= 0); - ks_assert(item); - - *distribute = d = ks_pool_alloc(pool, sizeof(ks_dht_distribute_t)); - ks_assert(d); - - d->pool = pool; - - d->callback = callback; - d->data = data; - ks_mutex_create(&d->mutex, KS_MUTEX_FLAG_DEFAULT, d->pool); - ks_assert(d->mutex); - d->cas = cas; - d->item = item; - - ks_dht_storageitem_reference(d->item); - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (d) ks_dht_distribute_destroy(distribute); - } - return ret; -} - -KS_DECLARE(void) ks_dht_distribute_destroy(ks_dht_distribute_t **distribute) -{ - ks_dht_distribute_t *d; - - ks_assert(distribute); - ks_assert(*distribute); - - d = *distribute; - - if (d->mutex) ks_mutex_destroy(&d->mutex); - ks_dht_storageitem_dereference(d->item); - - ks_pool_free(d->pool, distribute); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_endpoint.c b/libs/libblade/src/dht/ks_dht_endpoint.c deleted file mode 100644 index 3651bea39d..0000000000 --- a/libs/libblade/src/dht/ks_dht_endpoint.c +++ /dev/null @@ -1,61 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" -#include "sodium.h" - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_endpoint_create(ks_dht_endpoint_t **endpoint, - ks_pool_t *pool, - const ks_sockaddr_t *addr, - ks_socket_t sock) -{ - ks_dht_endpoint_t *ep; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(endpoint); - ks_assert(pool); - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - *endpoint = ep = ks_pool_alloc(pool, sizeof(ks_dht_endpoint_t)); - ks_assert(ep); - - ep->pool = pool; - ep->addr = *addr; - ep->sock = sock; - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (ep) ks_dht_endpoint_destroy(endpoint); - } - return ret; -} - -/** - * - */ -KS_DECLARE(void) ks_dht_endpoint_destroy(ks_dht_endpoint_t **endpoint) -{ - ks_dht_endpoint_t *ep; - - ks_assert(endpoint); - ks_assert(*endpoint); - - ep = *endpoint; - - if (ep->sock != KS_SOCK_INVALID) ks_socket_close(&ep->sock); - - ks_pool_free(ep->pool, endpoint); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_job.c b/libs/libblade/src/dht/ks_dht_job.c deleted file mode 100644 index 5aeaf08ec9..0000000000 --- a/libs/libblade/src/dht/ks_dht_job.c +++ /dev/null @@ -1,136 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" - -KS_DECLARE(ks_status_t) ks_dht_job_create(ks_dht_job_t **job, - ks_pool_t *pool, - const ks_sockaddr_t *raddr, - int32_t attempts, - void *data) -{ - ks_dht_job_t *j; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(job); - ks_assert(pool); - //ks_assert(dht); - ks_assert(attempts > 0 && attempts <= 10); - - *job = j = ks_pool_alloc(pool, sizeof(ks_dht_job_t)); - ks_assert(j); - - j->pool = pool; - j->state = KS_DHT_JOB_STATE_QUERYING; - if (raddr) j->raddr = *raddr; - j->attempts = attempts; - j->data = data; - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (j) ks_dht_job_destroy(job); - } - return ret; -} - -KS_DECLARE(void) ks_dht_job_build_ping(ks_dht_job_t *job, ks_dht_job_callback_t query_callback, ks_dht_job_callback_t finish_callback) -{ - ks_assert(job); - ks_assert(query_callback); - - job->query_callback = query_callback; - job->finish_callback = finish_callback; -} - -KS_DECLARE(void) ks_dht_job_build_findnode(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback, - ks_dht_nodeid_t *target) -{ - ks_assert(job); - ks_assert(query_callback); - ks_assert(target); - - job->query_callback = query_callback; - job->finish_callback = finish_callback; - job->query_target = *target; -} - -KS_DECLARE(void) ks_dht_job_build_get(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback, - ks_dht_nodeid_t *target, - const uint8_t *salt, - ks_size_t salt_length) -{ - ks_assert(job); - ks_assert(query_callback); - ks_assert(target); - - job->query_callback = query_callback; - job->finish_callback = finish_callback; - job->query_target = *target; - if (salt && salt_length > 0) job->query_salt = ben_blob(salt, salt_length); -} - -KS_DECLARE(void) ks_dht_job_build_put(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback, - ks_dht_token_t *token, - int64_t cas, - ks_dht_storageitem_t *item) -{ - ks_assert(job); - ks_assert(query_callback); - ks_assert(token); - ks_assert(item); - - job->query_callback = query_callback; - job->finish_callback = finish_callback; - job->query_token = *token; - job->query_cas = cas; - job->query_storageitem = item; - ks_dht_storageitem_reference(job->query_storageitem); -} - -KS_DECLARE(void) ks_dht_job_build_search(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback) -{ - ks_assert(job); - ks_assert(query_callback); - - job->query_callback = query_callback; - job->finish_callback = finish_callback; -} - -KS_DECLARE(void) ks_dht_job_destroy(ks_dht_job_t **job) -{ - ks_dht_job_t *j; - - ks_assert(job); - ks_assert(*job); - - j = *job; - - if (j->query_salt) ben_free(j->query_salt); - if (j->response_id) ks_dhtrt_release_node(j->response_id); - for (int32_t i = 0; i < j->response_nodes_count; ++i) ks_dhtrt_release_node(j->response_nodes[i]); - for (int32_t i = 0; i < j->response_nodes6_count; ++i) ks_dhtrt_release_node(j->response_nodes6[i]); - - if (j->query_storageitem) ks_dht_storageitem_dereference(j->query_storageitem); - if (j->response_storageitem) ks_dht_storageitem_dereference(j->response_storageitem); - - if (j->error_description) ben_free(j->error_description); - - ks_pool_free(j->pool, job); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_message.c b/libs/libblade/src/dht/ks_dht_message.c deleted file mode 100644 index 5cf29b7677..0000000000 --- a/libs/libblade/src/dht/ks_dht_message.c +++ /dev/null @@ -1,122 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" - -KS_DECLARE(ks_status_t) ks_dht_message_create(ks_dht_message_t **message, - ks_pool_t *pool, - ks_dht_endpoint_t *endpoint, - const ks_sockaddr_t *raddr, - ks_bool_t alloc_data) -{ - ks_dht_message_t *m; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(message); - ks_assert(pool); - - *message = m = ks_pool_alloc(pool, sizeof(ks_dht_message_t)); - ks_assert(m); - - m->pool = pool; - m->endpoint = endpoint; - m->raddr = *raddr; - if (alloc_data) { - m->data = ben_dict(); - ks_assert(m->data); - } - - // done: - if (ret != KS_STATUS_SUCCESS) { - ks_dht_message_destroy(message); - } - return ret; -} - -KS_DECLARE(void) ks_dht_message_destroy(ks_dht_message_t **message) -{ - ks_dht_message_t *m; - - ks_assert(message); - ks_assert(*message); - - m = *message; - - if (m->data) { - ben_free(m->data); - m->data = NULL; - } - - ks_pool_free(m->pool, message); -} - - -KS_DECLARE(ks_status_t) ks_dht_message_parse(ks_dht_message_t *message, const uint8_t *buffer, ks_size_t buffer_length) -{ - struct bencode *t; - struct bencode *y; - const char *tv; - const char *yv; - ks_size_t tv_len; - ks_size_t yv_len; - - ks_assert(message); - ks_assert(message->pool); - ks_assert(buffer); - ks_assert(!message->data); - - message->data = ben_decode((const void *)buffer, buffer_length); - if (!message->data) { - ks_log(KS_LOG_DEBUG, "Message cannot be decoded\n"); - return KS_STATUS_FAIL; - } - - ks_log(KS_LOG_DEBUG, "Message decoded\n"); - ks_log(KS_LOG_DEBUG, "%s\n", ben_print(message->data)); - - t = ben_dict_get_by_str(message->data, "t"); - if (!t) { - ks_log(KS_LOG_DEBUG, "Message missing required key 't'\n"); - return KS_STATUS_FAIL; - } - - tv = ben_str_val(t); - tv_len = ben_str_len(t); - if (tv_len > KS_DHT_MESSAGE_TRANSACTIONID_MAX_SIZE) { - ks_log(KS_LOG_DEBUG, "Message 't' value has an unexpectedly large size of %d\n", tv_len); - return KS_STATUS_FAIL; - } - - memcpy(message->transactionid, tv, tv_len); - message->transactionid_length = tv_len; - // @todo hex output of transactionid - //ks_log(KS_LOG_DEBUG, "Message transaction id is %d\n", message->transactionid); - - y = ben_dict_get_by_str(message->data, "y"); - if (!y) { - ks_log(KS_LOG_DEBUG, "Message missing required key 'y'\n"); - return KS_STATUS_FAIL; - } - - yv = ben_str_val(y); - yv_len = ben_str_len(y); - if (yv_len >= KS_DHT_MESSAGE_TYPE_MAX_SIZE) { - ks_log(KS_LOG_DEBUG, "Message 'y' value has an unexpectedly large size of %d\n", yv_len); - return KS_STATUS_FAIL; - } - - memcpy(message->type, yv, yv_len); - message->type[yv_len] = '\0'; - //ks_log(KS_LOG_DEBUG, "Message type is '%s'\n", message->type); - - return KS_STATUS_SUCCESS; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_publish.c b/libs/libblade/src/dht/ks_dht_publish.c deleted file mode 100644 index 8affdd5a40..0000000000 --- a/libs/libblade/src/dht/ks_dht_publish.c +++ /dev/null @@ -1,62 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" -#include "sodium.h" - -KS_DECLARE(ks_status_t) ks_dht_publish_create(ks_dht_publish_t **publish, - ks_pool_t *pool, - ks_dht_job_callback_t callback, - void *data, - int64_t cas, - ks_dht_storageitem_t *item) -{ - ks_dht_publish_t *p; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(publish); - ks_assert(pool); - ks_assert(cas >= 0); - ks_assert(item); - - *publish = p = ks_pool_alloc(pool, sizeof(ks_dht_publish_t)); - ks_assert(p); - - p->pool = pool; - - p->callback = callback; - p->data = data; - p->cas = cas; - p->item = item; - - ks_dht_storageitem_reference(p->item); - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (p) ks_dht_publish_destroy(publish); - } - return ret; -} - -KS_DECLARE(void) ks_dht_publish_destroy(ks_dht_publish_t **publish) -{ - ks_dht_publish_t *p; - - ks_assert(publish); - ks_assert(*publish); - - p = *publish; - - ks_dht_storageitem_dereference(p->item); - - ks_pool_free(p->pool, publish); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_search.c b/libs/libblade/src/dht/ks_dht_search.c deleted file mode 100644 index 5569d78425..0000000000 --- a/libs/libblade/src/dht/ks_dht_search.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" -#include "sodium.h" - -KS_DECLARE(ks_status_t) ks_dht_search_create(ks_dht_search_t **search, - ks_pool_t *pool, - ks_dhtrt_routetable_t *table, - const ks_dht_nodeid_t *target, - ks_dht_job_callback_t callback, - void *data) -{ - ks_dht_search_t *s; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(search); - ks_assert(pool); - ks_assert(table); - ks_assert(target); - - *search = s = ks_pool_alloc(pool, sizeof(ks_dht_search_t)); - ks_assert(s); - - s->pool = pool; - - ks_mutex_create(&s->mutex, KS_MUTEX_FLAG_DEFAULT, s->pool); - ks_assert(s->mutex); - - s->table = table; - memcpy(s->target.id, target->id, KS_DHT_NODEID_SIZE); - - s->callback = callback; - s->data = data; - - ks_hash_create(&s->searched, KS_HASH_MODE_ARBITRARY, KS_HASH_FLAG_NOLOCK | KS_HASH_FLAG_DUP_CHECK, s->pool); - ks_assert(s->searched); - ks_hash_set_keysize(s->searched, KS_DHT_NODEID_SIZE); - - s->searching = 0; - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (s) ks_dht_search_destroy(search); - } - return ret; -} - -KS_DECLARE(void) ks_dht_search_destroy(ks_dht_search_t **search) -{ - ks_dht_search_t *s; - - ks_assert(search); - ks_assert(*search); - - s = *search; - - if (s->searched) ks_hash_destroy(&s->searched); - if (s->mutex) ks_mutex_destroy(&s->mutex); - - ks_pool_free(s->pool, search); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_storageitem.c b/libs/libblade/src/dht/ks_dht_storageitem.c deleted file mode 100644 index 175e000968..0000000000 --- a/libs/libblade/src/dht/ks_dht_storageitem.c +++ /dev/null @@ -1,214 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" -#include "sodium.h" - -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_immutable_internal(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - struct bencode *v, - ks_bool_t clone_v) -{ - ks_dht_storageitem_t *si; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(item); - ks_assert(pool); - ks_assert(v); - ks_assert(SHA_DIGEST_LENGTH == KS_DHT_NODEID_SIZE); - - *item = si = ks_pool_alloc(pool, sizeof(ks_dht_storageitem_t)); - ks_assert(si); - - si->pool = pool; - si->id = *target; - si->mutable = KS_FALSE; - si->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - si->keepalive = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_KEEPALIVE * KS_USEC_PER_SEC); - si->v = clone_v ? ben_clone(v) : v; - ks_assert(si->v); - - si->refc = 1; - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (si) ks_dht_storageitem_destroy(item); - } - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_immutable(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - const uint8_t *value, - ks_size_t value_length) -{ - struct bencode *v = NULL; - - ks_assert(item); - ks_assert(pool); - ks_assert(value); - ks_assert(value_length > 0); - ks_assert(SHA_DIGEST_LENGTH == KS_DHT_NODEID_SIZE); - - v = ben_blob(value, value_length); - ks_assert(v); - - return ks_dht_storageitem_create_immutable_internal(item, pool, target, v, KS_FALSE); -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_mutable_internal(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - struct bencode *v, - ks_bool_t clone_v, - ks_dht_storageitem_pkey_t *pk, - struct bencode *salt, - ks_bool_t clone_salt, - int64_t sequence, - ks_dht_storageitem_signature_t *signature) -{ - ks_dht_storageitem_t *si; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(item); - ks_assert(pool); - ks_assert(v); - ks_assert(SHA_DIGEST_LENGTH == KS_DHT_NODEID_SIZE); - ks_assert(pk); - ks_assert(signature); - - *item = si = ks_pool_alloc(pool, sizeof(ks_dht_storageitem_t)); - ks_assert(si); - - si->pool = pool; - si->id = *target; - si->mutable = KS_TRUE; - si->expiration = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_EXPIRATION * KS_USEC_PER_SEC); - si->keepalive = ks_time_now() + ((ks_time_t)KS_DHT_STORAGEITEM_KEEPALIVE * KS_USEC_PER_SEC); - si->v = clone_v ? ben_clone(v) : v; - ks_assert(si->v); - - si->refc = 1; - - ks_mutex_create(&si->mutex, KS_MUTEX_FLAG_DEFAULT, si->pool); - ks_assert(si->mutex); - - si->pk = *pk; - if (salt) { - si->salt = clone_salt ? ben_clone(salt) : salt; - ks_assert(si->salt); - } - si->seq = sequence; - si->sig = *signature; - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (si) ks_dht_storageitem_destroy(item); - } - return ret; -} - -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_mutable(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - const uint8_t *value, - ks_size_t value_length, - ks_dht_storageitem_pkey_t *pk, - const uint8_t *salt, - ks_size_t salt_length, - int64_t sequence, - ks_dht_storageitem_signature_t *signature) -{ - struct bencode *v = NULL; - struct bencode *s = NULL; - - ks_assert(item); - ks_assert(pool); - ks_assert(value); - ks_assert(value_length > 0); - ks_assert(SHA_DIGEST_LENGTH == KS_DHT_NODEID_SIZE); - ks_assert(pk); - ks_assert(signature); - - v = ben_blob(value, value_length); - if (salt && salt_length > 0) s = ben_blob(salt, salt_length); - return ks_dht_storageitem_create_mutable_internal(item, pool, target, v, KS_FALSE, pk, s, KS_FALSE, sequence, signature); -} - -KS_DECLARE(void) ks_dht_storageitem_update_mutable(ks_dht_storageitem_t *item, struct bencode *v, int64_t sequence, ks_dht_storageitem_signature_t *signature) -{ - ks_assert(item); - ks_assert(v); - ks_assert(sequence); - ks_assert(signature); - - ks_mutex_lock(item->mutex); - ben_free(item->v); - item->v = ben_clone(v); - item->seq = sequence; - item->sig = *signature; - ks_mutex_unlock(item->mutex); -} - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitem_destroy(ks_dht_storageitem_t **item) -{ - ks_dht_storageitem_t *si; - - ks_assert(item); - ks_assert(*item); - - si = *item; - - if (si->v) { - ben_free(si->v); - si->v = NULL; - } - if (si->mutex) ks_mutex_destroy(&si->mutex); - if (si->salt) { - ben_free(si->salt); - si->salt = NULL; - } - - ks_pool_free(si->pool, item); -} - -KS_DECLARE(void) ks_dht_storageitem_reference(ks_dht_storageitem_t *item) -{ - ks_assert(item); - - ks_mutex_lock(item->mutex); - item->refc++; - ks_mutex_unlock(item->mutex); -} - -KS_DECLARE(void) ks_dht_storageitem_dereference(ks_dht_storageitem_t *item) -{ - ks_assert(item); - - ks_mutex_lock(item->mutex); - item->refc--; - ks_mutex_unlock(item->mutex); - - ks_assert(item->refc >= 0); -} - -KS_DECLARE(void) ks_dht_storageitem_callback(ks_dht_storageitem_t *item, ks_dht_storageitem_callback_t callback) -{ - ks_assert(item); - - item->callback = callback; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/dht/ks_dht_transaction.c b/libs/libblade/src/dht/ks_dht_transaction.c deleted file mode 100644 index 39dcd6a4d1..0000000000 --- a/libs/libblade/src/dht/ks_dht_transaction.c +++ /dev/null @@ -1,54 +0,0 @@ -#include "ks_dht.h" -#include "ks_dht-int.h" - -KS_DECLARE(ks_status_t) ks_dht_transaction_create(ks_dht_transaction_t **transaction, - ks_pool_t *pool, - ks_dht_job_t *job, - uint32_t transactionid, - ks_dht_job_callback_t callback) -{ - ks_dht_transaction_t *t; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(transaction); - ks_assert(pool); - ks_assert(job); - - *transaction = t = ks_pool_alloc(pool, sizeof(ks_dht_transaction_t)); - ks_assert(t); - - t->pool = pool; - t->job = job; - t->transactionid = transactionid; - t->callback = callback; - t->expiration = ks_time_now() + ((ks_time_t)KS_DHT_TRANSACTION_EXPIRATION * KS_USEC_PER_SEC); - - // done: - if (ret != KS_STATUS_SUCCESS) { - if (t) ks_dht_transaction_destroy(transaction); - } - return ret; -} - -KS_DECLARE(void) ks_dht_transaction_destroy(ks_dht_transaction_t **transaction) -{ - ks_dht_transaction_t *t; - - ks_assert(transaction); - ks_assert(*transaction); - - t = *transaction; - - ks_pool_free(t->pool, transaction); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade.h b/libs/libblade/src/include/blade.h deleted file mode 100644 index 5e1cb3db82..0000000000 --- a/libs/libblade/src/include/blade.h +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_H_ -#define _BLADE_H_ - -#include -#include -#include -#include -#include -#include "unqlite.h" -#include "blade_types.h" -#include "blade_stack.h" -#include "blade_identity.h" -#include "blade_transport.h" -#include "blade_rpc.h" -#include "blade_connection.h" -#include "blade_session.h" -#include "blade_protocol.h" -#include "blade_channel.h" -#include "blade_subscription.h" -#include "blade_tuple.h" -#include "blade_web.h" - -#include "blade_transportmgr.h" -#include "blade_rpcmgr.h" -#include "blade_routemgr.h" -#include "blade_subscriptionmgr.h" -#include "blade_mastermgr.h" -#include "blade_connectionmgr.h" -#include "blade_sessionmgr.h" -#include "blade_restmgr.h" - -#include "blade_transport_wss.h" - -KS_BEGIN_EXTERN_C - -// legacy for libconfig pre 1.5.0 -#if (LIBCONFIG_VER_MAJOR <= 1) && (LIBCONFIG_VER_MINOR <= 4) -#define config_setting_lookup config_lookup_from -#endif - -KS_DECLARE(ks_status_t) blade_init(void); -KS_DECLARE(ks_status_t) blade_shutdown(void); - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_channel.h b/libs/libblade/src/include/blade_channel.h deleted file mode 100644 index 660748dd36..0000000000 --- a/libs/libblade/src/include/blade_channel.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_CHANNEL_H_ -#define _BLADE_CHANNEL_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_channel_create(blade_channel_t **bcP, ks_pool_t *pool, const char *name, blade_channel_flags_t flags); -KS_DECLARE(ks_status_t) blade_channel_destroy(blade_channel_t **bcP); -KS_DECLARE(const char *) blade_channel_name_get(blade_channel_t *bc); -KS_DECLARE(blade_channel_flags_t) blade_channel_flags_get(blade_channel_t *bc); -KS_DECLARE(ks_status_t) blade_channel_read_lock(blade_channel_t *bc); -KS_DECLARE(ks_status_t) blade_channel_read_unlock(blade_channel_t *bc); -KS_DECLARE(ks_status_t) blade_channel_write_lock(blade_channel_t *bc); -KS_DECLARE(ks_status_t) blade_channel_write_unlock(blade_channel_t *bc); -KS_DECLARE(ks_bool_t) blade_channel_authorization_verify(blade_channel_t *bc, const char *target); -KS_DECLARE(ks_status_t) blade_channel_authorization_add(blade_channel_t *bc, const char *target); -KS_DECLARE(ks_bool_t) blade_channel_authorization_remove(blade_channel_t *bc, const char *target); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_connection.h b/libs/libblade/src/include/blade_connection.h deleted file mode 100644 index 960100ef4b..0000000000 --- a/libs/libblade/src/include/blade_connection.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_CONNECTION_H_ -#define _BLADE_CONNECTION_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_connection_create(blade_connection_t **bcP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_connection_destroy(blade_connection_t **bcP); -KS_DECLARE(ks_status_t) blade_connection_startup(blade_connection_t *bc, blade_connection_direction_t direction); -KS_DECLARE(ks_status_t) blade_connection_shutdown(blade_connection_t *bc); -KS_DECLARE(blade_handle_t *) blade_connection_handle_get(blade_connection_t *bc); -KS_DECLARE(const char *) blade_connection_id_get(blade_connection_t *bc); -KS_DECLARE(ks_status_t) blade_connection_read_lock(blade_connection_t *bc, ks_bool_t block); -KS_DECLARE(ks_status_t) blade_connection_read_unlock(blade_connection_t *bc); -KS_DECLARE(ks_status_t) blade_connection_write_lock(blade_connection_t *bc, ks_bool_t block); -KS_DECLARE(ks_status_t) blade_connection_write_unlock(blade_connection_t *bc); -KS_DECLARE(void *) blade_connection_transport_get(blade_connection_t *bc); -KS_DECLARE(void) blade_connection_transport_set(blade_connection_t *bc, void *transport_data, blade_transport_callbacks_t *transport_callbacks); -KS_DECLARE(void) blade_connection_state_set(blade_connection_t *bc, blade_connection_state_t state); -KS_DECLARE(blade_connection_state_t) blade_connection_state_get(blade_connection_t *bc); -KS_DECLARE(void) blade_connection_disconnect(blade_connection_t *bc); -KS_DECLARE(ks_status_t) blade_connection_sending_push(blade_connection_t *bc, cJSON *json); -KS_DECLARE(ks_status_t) blade_connection_sending_pop(blade_connection_t *bc, cJSON **json); -KS_DECLARE(const char *) blade_connection_session_get(blade_connection_t *bc); -KS_DECLARE(void) blade_connection_session_set(blade_connection_t *bc, const char *id); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_connectionmgr.h b/libs/libblade/src/include/blade_connectionmgr.h deleted file mode 100644 index 9d89a76a2e..0000000000 --- a/libs/libblade/src/include/blade_connectionmgr.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_CONNECTIONMGR_H_ -#define _BLADE_CONNECTIONMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_connectionmgr_create(blade_connectionmgr_t **bcmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_connectionmgr_destroy(blade_connectionmgr_t **bcmgrP); -KS_DECLARE(blade_handle_t *) blade_connectionmgr_handle_get(blade_connectionmgr_t *bcmgr); -KS_DECLARE(ks_status_t) blade_connectionmgr_shutdown(blade_connectionmgr_t *bcmgr); -KS_DECLARE(blade_connection_t *) blade_connectionmgr_connection_lookup(blade_connectionmgr_t *bcmgr, const char *id); -KS_DECLARE(ks_status_t) blade_connectionmgr_connection_add(blade_connectionmgr_t *bcmgr, blade_connection_t *bc); -KS_DECLARE(ks_status_t) blade_connectionmgr_connection_remove(blade_connectionmgr_t *bcmgr, blade_connection_t *bc); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_identity.h b/libs/libblade/src/include/blade_identity.h deleted file mode 100644 index bdef1d203e..0000000000 --- a/libs/libblade/src/include/blade_identity.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_IDENTITY_H_ -#define _BLADE_IDENTITY_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_identity_create(blade_identity_t **biP, ks_pool_t *pool); -KS_DECLARE(ks_status_t) blade_identity_destroy(blade_identity_t **biP); -KS_DECLARE(ks_status_t) blade_identity_parse(blade_identity_t *bi, const char *uri); -KS_DECLARE(const char *) blade_identity_uri_get(blade_identity_t *bi); -KS_DECLARE(const char *) blade_identity_scheme_get(blade_identity_t *bi); -KS_DECLARE(const char *) blade_identity_user_get(blade_identity_t *bi); -KS_DECLARE(const char *) blade_identity_host_get(blade_identity_t *bi); -KS_DECLARE(const char *) blade_identity_port_get(blade_identity_t *bi); -KS_DECLARE(ks_port_t) blade_identity_portnum_get(blade_identity_t *bi); -KS_DECLARE(const char *) blade_identity_path_get(blade_identity_t *bi); -KS_DECLARE(const char *) blade_identity_parameter_lookup(blade_identity_t *bi, const char *key); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_mastermgr.h b/libs/libblade/src/include/blade_mastermgr.h deleted file mode 100644 index 11242aee9a..0000000000 --- a/libs/libblade/src/include/blade_mastermgr.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_MASTERMGR_H_ -#define _BLADE_MASTERMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_mastermgr_create(blade_mastermgr_t **bmmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_mastermgr_destroy(blade_mastermgr_t **bmmgrP); -KS_DECLARE(ks_status_t) blade_mastermgr_startup(blade_mastermgr_t *bmmgr, config_setting_t *config); -KS_DECLARE(ks_status_t) blade_mastermgr_shutdown(blade_mastermgr_t *bmmgr); -KS_DECLARE(blade_handle_t *) blade_mastermgr_handle_get(blade_mastermgr_t *bmmgr); -KS_DECLARE(ks_status_t) blade_mastermgr_purge(blade_mastermgr_t *bmmgr, const char *nodeid); -KS_DECLARE(blade_protocol_t *) blade_mastermgr_protocol_lookup(blade_mastermgr_t *bmmgr, const char *protocol, ks_bool_t writelocked); -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_controller_add(blade_mastermgr_t *bmmgr, const char *protocol, const char *controller); -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_controller_remove(blade_mastermgr_t *bmmgr, const char *protocol, const char *controller); -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_channel_add(blade_mastermgr_t *bmmgr, const char *protocol, const char *channel, blade_channel_flags_t flags); -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_channel_remove(blade_mastermgr_t *bmmgr, const char *protocol, const char *channel); -KS_DECLARE(ks_status_t) blade_mastermgr_protocol_channel_authorize(blade_mastermgr_t *bmmgr, ks_bool_t remove, const char *protocol, const char *channel, const char *controller, const char *target); -KS_DECLARE(ks_bool_t) blade_mastermgr_protocol_channel_authorization_verify(blade_mastermgr_t *bmmgr, const char *protocol, const char *channel, const char *target); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_protocol.h b/libs/libblade/src/include/blade_protocol.h deleted file mode 100644 index bb59a1da63..0000000000 --- a/libs/libblade/src/include/blade_protocol.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_PROTOCOL_H_ -#define _BLADE_PROTOCOL_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_protocol_create(blade_protocol_t **bpP, ks_pool_t *pool, const char *name); -KS_DECLARE(ks_status_t) blade_protocol_destroy(blade_protocol_t **bpP); -KS_DECLARE(const char *) blade_protocol_name_get(blade_protocol_t *bp); -KS_DECLARE(ks_status_t) blade_protocol_read_lock(blade_protocol_t *bp); -KS_DECLARE(ks_status_t) blade_protocol_read_unlock(blade_protocol_t *bp); -KS_DECLARE(ks_status_t) blade_protocol_write_lock(blade_protocol_t *bp); -KS_DECLARE(ks_status_t) blade_protocol_write_unlock(blade_protocol_t *bp); -KS_DECLARE(ks_bool_t) blade_protocol_purge(blade_protocol_t *bp, const char *nodeid); -KS_DECLARE(cJSON *) blade_protocol_controller_pack(blade_protocol_t *bp); -KS_DECLARE(ks_status_t) blade_protocol_controller_add(blade_protocol_t *bp, const char *nodeid); -KS_DECLARE(ks_bool_t) blade_protocol_controller_remove(blade_protocol_t *bp, const char *nodeid); -KS_DECLARE(ks_bool_t) blade_protocol_controller_available(blade_protocol_t *bp); -KS_DECLARE(blade_channel_t *) blade_protocol_channel_lookup(blade_protocol_t *bp, const char *channel, ks_bool_t writelocked); -KS_DECLARE(ks_bool_t) blade_protocol_controller_verify(blade_protocol_t *bp, const char *controller); -KS_DECLARE(ks_status_t) blade_protocol_channel_add(blade_protocol_t *bp, blade_channel_t *channel); -KS_DECLARE(ks_bool_t) blade_protocol_channel_remove(blade_protocol_t *bp, const char *channel); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_restmgr.h b/libs/libblade/src/include/blade_restmgr.h deleted file mode 100644 index 87b5e9aa7d..0000000000 --- a/libs/libblade/src/include/blade_restmgr.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_RESTMGR_H_ -#define _BLADE_RESTMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_restmgr_create(blade_restmgr_t **brestmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_restmgr_destroy(blade_restmgr_t **brestmgrP); -KS_DECLARE(ks_status_t) blade_restmgr_startup(blade_restmgr_t *brestmgr, config_setting_t *config); -KS_DECLARE(ks_status_t) blade_restmgr_shutdown(blade_restmgr_t *brestmgr); -KS_DECLARE(blade_handle_t *) blade_restmgr_handle_get(blade_restmgr_t *brestmgr); -KS_DECLARE(void *) blade_restmgr_data_get(blade_restmgr_t *brestmgr); -KS_DECLARE(ks_status_t) blade_restmgr_data_set(blade_restmgr_t *brestmgr, void *data); -KS_DECLARE(ks_status_t) blade_restmgr_service_add(blade_restmgr_t *brestmgr, const char *action, const char *route, blade_restmgr_service_callback_t callback); -KS_DECLARE(ks_status_t) blade_restmgr_service_remove(blade_restmgr_t *brestmgr, const char *action, const char *route); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_routemgr.h b/libs/libblade/src/include/blade_routemgr.h deleted file mode 100644 index d1e930b657..0000000000 --- a/libs/libblade/src/include/blade_routemgr.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_ROUTEMGR_H_ -#define _BLADE_ROUTEMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_routemgr_create(blade_routemgr_t **brmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_routemgr_destroy(blade_routemgr_t **brmgrP); -KS_DECLARE(blade_handle_t *) blade_routemgr_handle_get(blade_routemgr_t *brmgr); -KS_DECLARE(ks_status_t) blade_routemgr_local_set(blade_routemgr_t *brmgr, const char *nodeid); -KS_DECLARE(ks_bool_t) blade_routemgr_local_check(blade_routemgr_t *brmgr, const char *target); -KS_DECLARE(ks_bool_t) blade_routemgr_local_copy(blade_routemgr_t *brmgr, const char **nodeid); -KS_DECLARE(ks_bool_t) blade_routemgr_local_pack(blade_routemgr_t *brmgr, cJSON *json, const char *key); -KS_DECLARE(ks_status_t) blade_routemgr_master_set(blade_routemgr_t *brmgr, const char *nodeid); -KS_DECLARE(ks_bool_t) blade_routemgr_master_check(blade_routemgr_t *brmgr, const char *target); -KS_DECLARE(ks_bool_t) blade_routemgr_master_pack(blade_routemgr_t *brmgr, cJSON *json, const char *key); -KS_DECLARE(ks_bool_t) blade_routemgr_master_local(blade_routemgr_t *brmgr); -KS_DECLARE(blade_session_t *) blade_routemgr_route_lookup(blade_routemgr_t *brmgr, const char *target); -KS_DECLARE(ks_status_t) blade_routemgr_route_add(blade_routemgr_t *brmgr, const char *target, const char *router); -KS_DECLARE(ks_status_t) blade_routemgr_route_remove(blade_routemgr_t *brmgr, const char *target); -KS_DECLARE(ks_status_t) blade_routemgr_identity_add(blade_routemgr_t *brmgr, blade_identity_t *identity, const char *target); -KS_DECLARE(ks_status_t) blade_routemgr_identity_remove(blade_routemgr_t *brmgr, blade_identity_t *identity, const char *target); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_rpc.h b/libs/libblade/src/include/blade_rpc.h deleted file mode 100644 index a381794368..0000000000 --- a/libs/libblade/src/include/blade_rpc.h +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_RPC_H_ -#define _BLADE_RPC_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_rpc_create(blade_rpc_t **brpcP, blade_handle_t *bh, const char *method, const char *protocol, blade_rpc_request_callback_t callback, void *data); -KS_DECLARE(ks_status_t) blade_rpc_destroy(blade_rpc_t **brpcP); -KS_DECLARE(blade_handle_t *) blade_rpc_handle_get(blade_rpc_t *brpc); -KS_DECLARE(const char *) blade_rpc_method_get(blade_rpc_t *brpc); -KS_DECLARE(const char *) blade_rpc_protocol_get(blade_rpc_t *brpc); -KS_DECLARE(blade_rpc_request_callback_t) blade_rpc_callback_get(blade_rpc_t *brpc); -KS_DECLARE(void *) blade_rpc_data_get(blade_rpc_t *brpc); - -KS_DECLARE(ks_status_t) blade_rpc_request_create(blade_rpc_request_t **brpcreqP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - cJSON *json, - blade_rpc_response_callback_t callback, - void *data); -KS_DECLARE(ks_status_t) blade_rpc_request_destroy(blade_rpc_request_t **brpcreqP); -KS_DECLARE(ks_status_t) blade_rpc_request_duplicate(blade_rpc_request_t **brpcreqP, blade_rpc_request_t *brpcreq); -KS_DECLARE(blade_handle_t *) blade_rpc_request_handle_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(const char *) blade_rpc_request_sessionid_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(cJSON *) blade_rpc_request_message_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(const char *) blade_rpc_request_messageid_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(ks_status_t) blade_rpc_request_ttl_set(blade_rpc_request_t *brpcreq, ks_time_t ttl); -KS_DECLARE(ks_bool_t) blade_rpc_request_expired(blade_rpc_request_t *brpcreq); -KS_DECLARE(blade_rpc_response_callback_t) blade_rpc_request_callback_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(void *) blade_rpc_request_data_get(blade_rpc_request_t *brpcreq); - -KS_DECLARE(ks_status_t) blade_rpc_request_raw_create(ks_pool_t *pool, cJSON **json, cJSON **params, const char **id, const char *method); - -KS_DECLARE(ks_status_t) blade_rpc_response_create(blade_rpc_response_t **brpcresP, - blade_handle_t *bh, - ks_pool_t *pool, - const char *session_id, - blade_rpc_request_t *brpcreq, - cJSON *json); -KS_DECLARE(ks_status_t) blade_rpc_response_destroy(blade_rpc_response_t **brpcresP); -KS_DECLARE(ks_status_t) blade_rpc_response_raw_create(cJSON **json, cJSON **result, const char *id); -KS_DECLARE(blade_handle_t *) blade_rpc_response_handle_get(blade_rpc_response_t *brpcres); -KS_DECLARE(const char *) blade_rpc_response_sessionid_get(blade_rpc_response_t *brpcres); -KS_DECLARE(blade_rpc_request_t *) blade_rpc_response_request_get(blade_rpc_response_t *brpcres); -KS_DECLARE(cJSON *) blade_rpc_response_message_get(blade_rpc_response_t *brpcres); - -KS_DECLARE(ks_status_t) blade_rpc_error_raw_create(cJSON **json, cJSON **error, const char *id, int32_t code, const char *message); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_rpcmgr.h b/libs/libblade/src/include/blade_rpcmgr.h deleted file mode 100644 index 646815d389..0000000000 --- a/libs/libblade/src/include/blade_rpcmgr.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_RPCMGR_H_ -#define _BLADE_RPCMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_rpcmgr_create(blade_rpcmgr_t **brpcmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_rpcmgr_destroy(blade_rpcmgr_t **brpcmgrP); -KS_DECLARE(blade_handle_t *) blade_rpcmgr_handle_get(blade_rpcmgr_t *brpcmgr); -KS_DECLARE(blade_rpc_t *) blade_rpcmgr_corerpc_lookup(blade_rpcmgr_t *brpcmgr, const char *method); -KS_DECLARE(ks_status_t) blade_rpcmgr_corerpc_add(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc); -KS_DECLARE(ks_status_t) blade_rpcmgr_corerpc_remove(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc); -KS_DECLARE(blade_rpc_t *) blade_rpcmgr_protocolrpc_lookup(blade_rpcmgr_t *brpcmgr, const char *method, const char *protocol); -KS_DECLARE(ks_status_t) blade_rpcmgr_protocolrpc_add(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc); -KS_DECLARE(ks_status_t) blade_rpcmgr_protocolrpc_remove(blade_rpcmgr_t *brpcmgr, blade_rpc_t *brpc); -KS_DECLARE(blade_rpc_request_t *) blade_rpcmgr_request_lookup(blade_rpcmgr_t *brpcmgr, const char *id); -KS_DECLARE(ks_status_t) blade_rpcmgr_request_add(blade_rpcmgr_t *brpcmgr, blade_rpc_request_t *brpcreq); -KS_DECLARE(ks_status_t) blade_rpcmgr_request_remove(blade_rpcmgr_t *brpcmgr, blade_rpc_request_t *brpcreq); -KS_DECLARE(ks_status_t) blade_rpcmgr_request_timeouts(blade_rpcmgr_t *brpcmgr); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_session.h b/libs/libblade/src/include/blade_session.h deleted file mode 100644 index 0a292fc08b..0000000000 --- a/libs/libblade/src/include/blade_session.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_SESSION_H_ -#define _BLADE_SESSION_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_session_create(blade_session_t **bsP, blade_handle_t *bh, blade_session_flags_t flags, const char *sessionid); -KS_DECLARE(ks_status_t) blade_session_destroy(blade_session_t **bsP); -KS_DECLARE(ks_status_t) blade_session_startup(blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_session_shutdown(blade_session_t *bs); -KS_DECLARE(blade_handle_t *) blade_session_handle_get(blade_session_t *bs); -KS_DECLARE(ks_bool_t) blade_session_loopback(blade_session_t *bs); -KS_DECLARE(ks_bool_t) blade_session_upstream(blade_session_t *bs); -KS_DECLARE(const char *) blade_session_id_get(blade_session_t *bs); -KS_DECLARE(blade_session_state_t) blade_session_state_get(blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_session_route_add(blade_session_t *bs, const char *nodeid); -KS_DECLARE(ks_status_t) blade_session_route_remove(blade_session_t *bs, const char *nodeid); -KS_DECLARE(cJSON *) blade_session_properties_get(blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_session_read_lock(blade_session_t *bs, ks_bool_t block); -KS_DECLARE(ks_status_t) blade_session_read_unlock(blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_session_write_lock(blade_session_t *bs, ks_bool_t block); -KS_DECLARE(ks_status_t) blade_session_write_unlock(blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_session_properties_read_lock(blade_session_t *bs, ks_bool_t block); -KS_DECLARE(ks_status_t) blade_session_properties_read_unlock(blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_session_properties_write_lock(blade_session_t *bs, ks_bool_t block); -KS_DECLARE(ks_status_t) blade_session_properties_write_unlock(blade_session_t *bs); -KS_DECLARE(void) blade_session_state_set(blade_session_t *bs, blade_session_state_t state); -KS_DECLARE(void) blade_session_hangup(blade_session_t *bs); -KS_DECLARE(ks_bool_t) blade_session_terminating(blade_session_t *bs); -KS_DECLARE(const char *) blade_session_connection_get(blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_session_connection_set(blade_session_t *bs, const char *id); -KS_DECLARE(ks_status_t) blade_session_send(blade_session_t *bs, cJSON *json, ks_time_t ttl, blade_rpc_response_callback_t callback, void *data); -KS_DECLARE(ks_status_t) blade_session_sending_push(blade_session_t *bs, cJSON *json); -KS_DECLARE(ks_status_t) blade_session_sending_pop(blade_session_t *bs, cJSON **json); -KS_DECLARE(ks_status_t) blade_session_receiving_push(blade_session_t *bs, cJSON *json); -KS_DECLARE(ks_status_t) blade_session_receiving_pop(blade_session_t *bs, cJSON **json); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_sessionmgr.h b/libs/libblade/src/include/blade_sessionmgr.h deleted file mode 100644 index 9666142a14..0000000000 --- a/libs/libblade/src/include/blade_sessionmgr.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_SESSIONMGR_H_ -#define _BLADE_SESSIONMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_sessionmgr_create(blade_sessionmgr_t **bsmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_sessionmgr_destroy(blade_sessionmgr_t **bsmgrP); -KS_DECLARE(blade_handle_t *) blade_sessionmgr_handle_get(blade_sessionmgr_t *bsmgr); -KS_DECLARE(ks_status_t) blade_sessionmgr_startup(blade_sessionmgr_t *bsmgr, config_setting_t *config); -KS_DECLARE(ks_status_t) blade_sessionmgr_shutdown(blade_sessionmgr_t *bsmgr); -KS_DECLARE(blade_session_t *) blade_sessionmgr_loopback_lookup(blade_sessionmgr_t *bsmgr); -KS_DECLARE(blade_session_t *) blade_sessionmgr_upstream_lookup(blade_sessionmgr_t *bsmgr); -KS_DECLARE(blade_session_t *) blade_sessionmgr_session_lookup(blade_sessionmgr_t *bsmgr, const char *id); -KS_DECLARE(ks_status_t) blade_sessionmgr_session_add(blade_sessionmgr_t *bsmgr, blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_sessionmgr_session_remove(blade_sessionmgr_t *bsmgr, blade_session_t *bs); -KS_DECLARE(ks_status_t) blade_sessionmgr_callback_add(blade_sessionmgr_t *bsmgr, void *data, blade_session_callback_t callback, const char **id); -KS_DECLARE(ks_status_t) blade_sessionmgr_callback_remove(blade_sessionmgr_t *bsmgr, const char *id); -KS_DECLARE(void) blade_sessionmgr_callback_execute(blade_sessionmgr_t *bsmgr, blade_session_t *bs, blade_session_state_condition_t condition); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_stack.h b/libs/libblade/src/include/blade_stack.h deleted file mode 100644 index 3a5e4edbf6..0000000000 --- a/libs/libblade/src/include/blade_stack.h +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_STACK_H_ -#define _BLADE_STACK_H_ -#include - -#define BLADE_HANDLE_TPOOL_MIN 2 -#define BLADE_HANDLE_TPOOL_MAX 4096 -#define BLADE_HANDLE_TPOOL_STACK (1024 * 256) -#define BLADE_HANDLE_TPOOL_IDLE 10 - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_handle_destroy(blade_handle_t **bhP); -KS_DECLARE(ks_status_t) blade_handle_create(blade_handle_t **bhP); -KS_DECLARE(ks_status_t) blade_handle_startup(blade_handle_t *bh, config_setting_t *config); -KS_DECLARE(ks_status_t) blade_handle_shutdown(blade_handle_t *bh); -KS_DECLARE(ks_thread_pool_t *) blade_handle_tpool_get(blade_handle_t *bh); - -KS_DECLARE(blade_transportmgr_t *) blade_handle_transportmgr_get(blade_handle_t *bh); -KS_DECLARE(blade_rpcmgr_t *) blade_handle_rpcmgr_get(blade_handle_t *bh); -KS_DECLARE(blade_routemgr_t *) blade_handle_routemgr_get(blade_handle_t *bh); -KS_DECLARE(blade_subscriptionmgr_t *) blade_handle_subscriptionmgr_get(blade_handle_t *bh); -KS_DECLARE(blade_mastermgr_t *) blade_handle_mastermgr_get(blade_handle_t *bh); -KS_DECLARE(blade_connectionmgr_t *) blade_handle_connectionmgr_get(blade_handle_t *bh); -KS_DECLARE(blade_sessionmgr_t *) blade_handle_sessionmgr_get(blade_handle_t *bh); -KS_DECLARE(blade_restmgr_t *) blade_handle_restmgr_get(blade_handle_t *bh); - -KS_DECLARE(ks_status_t) blade_handle_connect(blade_handle_t *bh, blade_connection_t **bcP, blade_identity_t *target, const char *session_id); - -KS_DECLARE(ks_status_t) blade_handle_rpcroute(blade_handle_t *bh, const char *nodeid, ks_bool_t remove, blade_rpc_response_callback_t callback, void *data); - -KS_DECLARE(ks_status_t) blade_handle_rpcregister(blade_handle_t *bh, const char *identity, blade_rpc_response_callback_t callback, void *data); - -KS_DECLARE(ks_status_t) blade_handle_rpcpublish(blade_handle_t *bh, blade_rpcpublish_command_t command, const char *protocol, cJSON *channels, blade_rpc_response_callback_t callback, void *data); - -KS_DECLARE(ks_status_t) blade_handle_rpcauthorize(blade_handle_t *bh, const char *nodeid, ks_bool_t remove, const char *protocol, cJSON *channels, blade_rpc_response_callback_t callback, void *data); - -KS_DECLARE(ks_status_t) blade_handle_rpclocate(blade_handle_t *bh, const char *protocol, blade_rpc_response_callback_t callback, void *data); - -KS_DECLARE(ks_status_t) blade_handle_rpcexecute(blade_handle_t *bh, const char *nodeid, const char *method, const char *protocol, cJSON *params, ks_time_t ttl, blade_rpc_response_callback_t callback, void *data); -KS_DECLARE(const char *) blade_rpcexecute_request_requester_nodeid_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(const char *) blade_rpcexecute_request_responder_nodeid_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(cJSON *) blade_rpcexecute_request_params_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(cJSON *) blade_rpcexecute_response_result_get(blade_rpc_response_t *brpcres); -KS_DECLARE(void) blade_rpcexecute_response_send(blade_rpc_request_t *brpcreq, cJSON *result); - -KS_DECLARE(ks_status_t) blade_handle_rpcsubscribe(blade_handle_t *bh, blade_rpcsubscribe_command_t command, const char *protocol, cJSON *channels, blade_rpc_response_callback_t callback, void *data, blade_rpc_request_callback_t channel_callback, void *channel_data); - -KS_DECLARE(ks_status_t) blade_handle_rpcbroadcast(blade_handle_t *bh, const char *protocol, const char *channel, const char *event, cJSON *params, blade_rpc_response_callback_t callback, void *data); -KS_DECLARE(cJSON *) blade_rpcbroadcast_request_params_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(const char *) blade_rpcbroadcast_request_protocol_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(const char *) blade_rpcbroadcast_request_channel_get(blade_rpc_request_t *brpcreq); -KS_DECLARE(const char *) blade_rpcbroadcast_request_event_get(blade_rpc_request_t *brpcreq); - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_subscription.h b/libs/libblade/src/include/blade_subscription.h deleted file mode 100644 index 5c591941bd..0000000000 --- a/libs/libblade/src/include/blade_subscription.h +++ /dev/null @@ -1,63 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_SUBSCRIPTION_H_ -#define _BLADE_SUBSCRIPTION_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_subscription_create(blade_subscription_t **bsubP, ks_pool_t *pool, const char *protocol, const char *channel); -KS_DECLARE(ks_status_t) blade_subscription_destroy(blade_subscription_t **bsubP); -KS_DECLARE(const char *) blade_subscription_protocol_get(blade_subscription_t *bsub); -KS_DECLARE(const char *) blade_subscription_channel_get(blade_subscription_t *bsub); -KS_DECLARE(ks_hash_t *) blade_subscription_subscribers_get(blade_subscription_t *bsub); -KS_DECLARE(ks_status_t) blade_subscription_subscribers_add(blade_subscription_t *bsub, const char *nodeid); -KS_DECLARE(ks_status_t) blade_subscription_subscribers_remove(blade_subscription_t *bsub, const char *nodeid); -KS_DECLARE(blade_rpc_request_callback_t) blade_subscription_callback_get(blade_subscription_t *bsub); -KS_DECLARE(void) blade_subscription_callback_set(blade_subscription_t *bsub, blade_rpc_request_callback_t callback); -KS_DECLARE(void *) blade_subscription_callback_data_get(blade_subscription_t *bsub); -KS_DECLARE(void) blade_subscription_callback_data_set(blade_subscription_t *bsub, void *data); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_subscriptionmgr.h b/libs/libblade/src/include/blade_subscriptionmgr.h deleted file mode 100644 index ace7db8887..0000000000 --- a/libs/libblade/src/include/blade_subscriptionmgr.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_SUBSCRIPTIONMGR_H_ -#define _BLADE_SUBSCRIPTIONMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_subscriptionmgr_create(blade_subscriptionmgr_t **bsmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_subscriptionmgr_destroy(blade_subscriptionmgr_t **bsmgrP); -KS_DECLARE(blade_handle_t *) blade_subscriptionmgr_handle_get(blade_subscriptionmgr_t *bsmgr); -KS_DECLARE(blade_subscription_t *) blade_subscriptionmgr_subscription_lookup(blade_subscriptionmgr_t *bsmgr, const char *protocol, const char *channel); -KS_DECLARE(ks_status_t) blade_subscriptionmgr_subscription_remove(blade_subscriptionmgr_t *bsmgr, const char *protocol, const char *channel); -KS_DECLARE(ks_bool_t) blade_subscriptionmgr_subscriber_add(blade_subscriptionmgr_t *bsmgr, blade_subscription_t **bsubP, const char *protocol, const char *channel, const char *subscriber); -KS_DECLARE(ks_bool_t) blade_subscriptionmgr_subscriber_remove(blade_subscriptionmgr_t *bsmgr, blade_subscription_t **bsubP, const char *protocol, const char *channel, const char *subscriber); -KS_DECLARE(void) blade_subscriptionmgr_purge(blade_subscriptionmgr_t *bsmgr, const char *target); -KS_DECLARE(ks_status_t) blade_subscriptionmgr_broadcast(blade_subscriptionmgr_t *bsmgr, blade_rpcbroadcast_command_t command, const char *excluded_sessionid, const char *protocol, const char *channel, const char *event, cJSON *params, blade_rpc_response_callback_t callback, void *data); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_transport.h b/libs/libblade/src/include/blade_transport.h deleted file mode 100644 index 7b90202ca0..0000000000 --- a/libs/libblade/src/include/blade_transport.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_TRANSPORT_H_ -#define _BLADE_TRANSPORT_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_transport_create(blade_transport_t **btP, blade_handle_t *bh, ks_pool_t *pool, const char *name, void *data, blade_transport_callbacks_t *callbacks); -KS_DECLARE(ks_status_t) blade_transport_destroy(blade_transport_t **btP); -KS_DECLARE(blade_handle_t *) blade_transport_handle_get(blade_transport_t *bt); -KS_DECLARE(const char *) blade_transport_name_get(blade_transport_t *bt); -KS_DECLARE(void *) blade_transport_data_get(blade_transport_t *bt); -KS_DECLARE(blade_transport_callbacks_t *) blade_transport_callbacks_get(blade_transport_t *bt); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_transport_wss.h b/libs/libblade/src/include/blade_transport_wss.h deleted file mode 100644 index 07ab49fecd..0000000000 --- a/libs/libblade/src/include/blade_transport_wss.h +++ /dev/null @@ -1,55 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_TRANSPORT_WSS_H_ -#define _BLADE_TRANSPORT_WSS_H_ -#include - -KS_BEGIN_EXTERN_C - -KS_DECLARE(ks_status_t) blade_transport_wss_create(blade_transport_t **btP, blade_handle_t *bh); - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_transportmgr.h b/libs/libblade/src/include/blade_transportmgr.h deleted file mode 100644 index dd7b9c1539..0000000000 --- a/libs/libblade/src/include/blade_transportmgr.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_TRANSPORTMGR_H_ -#define _BLADE_TRANSPORTMGR_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_transportmgr_create(blade_transportmgr_t **btmgrP, blade_handle_t *bh); -KS_DECLARE(ks_status_t) blade_transportmgr_destroy(blade_transportmgr_t **btmgrP); -KS_DECLARE(ks_status_t) blade_transportmgr_startup(blade_transportmgr_t *btmgr, config_setting_t *config); -KS_DECLARE(ks_status_t) blade_transportmgr_shutdown(blade_transportmgr_t *btmgr); -KS_DECLARE(blade_handle_t *) blade_transportmgr_handle_get(blade_transportmgr_t *btmgr); -KS_DECLARE(blade_transport_t *) blade_transportmgr_default_get(blade_transportmgr_t *btmgr); -KS_DECLARE(ks_status_t) blade_transportmgr_default_set(blade_transportmgr_t *btmgr, blade_transport_t *bt); -KS_DECLARE(blade_transport_t *) blade_transportmgr_transport_lookup(blade_transportmgr_t *btmgr, const char *name, ks_bool_t ordefault); -KS_DECLARE(ks_status_t) blade_transportmgr_transport_add(blade_transportmgr_t *btmgr, blade_transport_t *bt); -KS_DECLARE(ks_status_t) blade_transportmgr_transport_remove(blade_transportmgr_t *btmgr, blade_transport_t *bt); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_tuple.h b/libs/libblade/src/include/blade_tuple.h deleted file mode 100644 index 28cd2b71f2..0000000000 --- a/libs/libblade/src/include/blade_tuple.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_TUPLE_H_ -#define _BLADE_TUPLE_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_tuple_create(blade_tuple_t **btP, ks_pool_t *pool, void *value1, void *value2); -KS_DECLARE(ks_status_t) blade_tuple_destroy(blade_tuple_t **btP); -KS_DECLARE(void *) blade_tuple_value1_get(blade_tuple_t *bt); -KS_DECLARE(void *) blade_tuple_value2_get(blade_tuple_t *bt); -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_types.h b/libs/libblade/src/include/blade_types.h deleted file mode 100644 index 2003e3dfbb..0000000000 --- a/libs/libblade/src/include/blade_types.h +++ /dev/null @@ -1,185 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_TYPES_H_ -#define _BLADE_TYPES_H_ -#include -#include - -KS_BEGIN_EXTERN_C - -typedef struct blade_handle_s blade_handle_t; -typedef struct blade_identity_s blade_identity_t; -typedef struct blade_transport_s blade_transport_t; -typedef struct blade_transport_callbacks_s blade_transport_callbacks_t; -typedef struct blade_rpc_s blade_rpc_t; -typedef struct blade_rpc_request_s blade_rpc_request_t; -typedef struct blade_rpc_response_s blade_rpc_response_t; -typedef struct blade_connection_s blade_connection_t; -typedef struct blade_session_s blade_session_t; -typedef struct blade_session_callbacks_s blade_session_callbacks_t; -typedef struct blade_protocol_s blade_protocol_t; -typedef struct blade_channel_s blade_channel_t; -typedef struct blade_subscription_s blade_subscription_t; -typedef struct blade_tuple_s blade_tuple_t; - -typedef struct blade_transportmgr_s blade_transportmgr_t; -typedef struct blade_rpcmgr_s blade_rpcmgr_t; -typedef struct blade_routemgr_s blade_routemgr_t; -typedef struct blade_subscriptionmgr_s blade_subscriptionmgr_t; -typedef struct blade_mastermgr_s blade_mastermgr_t; -typedef struct blade_connectionmgr_s blade_connectionmgr_t; -typedef struct blade_sessionmgr_s blade_sessionmgr_t; -typedef struct blade_session_callback_data_s blade_session_callback_data_t; - -typedef struct blade_webrequest_s blade_webrequest_t; -typedef struct blade_webresponse_s blade_webresponse_t; -typedef struct blade_restmgr_s blade_restmgr_t; - -typedef ks_bool_t (*blade_rpc_request_callback_t)(blade_rpc_request_t *brpcreq, void *data); -typedef ks_bool_t (*blade_rpc_response_callback_t)(blade_rpc_response_t *brpcres, void *data); - -typedef int (*blade_restmgr_service_callback_t)(blade_restmgr_t *brestmgr, struct mg_connection *conn, const char **captures); - -typedef enum { - BLADE_CONNECTION_STATE_NONE, - BLADE_CONNECTION_STATE_CLEANUP, - BLADE_CONNECTION_STATE_STARTUP, - BLADE_CONNECTION_STATE_SHUTDOWN, - BLADE_CONNECTION_STATE_RUN, -} blade_connection_state_t; - -typedef enum { - BLADE_CONNECTION_DIRECTION_INBOUND, - BLADE_CONNECTION_DIRECTION_OUTBOUND, -} blade_connection_direction_t; - -typedef enum { - BLADE_CONNECTION_STATE_CONDITION_PRE, - BLADE_CONNECTION_STATE_CONDITION_POST, -} blade_connection_state_condition_t; - -typedef enum { - BLADE_CONNECTION_STATE_HOOK_SUCCESS, - BLADE_CONNECTION_STATE_HOOK_DISCONNECT, - BLADE_CONNECTION_STATE_HOOK_BYPASS, -} blade_connection_state_hook_t; - -typedef enum { - BLADE_SESSION_FLAGS_NONE = 0 << 0, - BLADE_SESSION_FLAGS_LOOPBACK = 1 << 0, - BLADE_SESSION_FLAGS_UPSTREAM = 1 << 1, -} blade_session_flags_t; - -typedef enum { - BLADE_SESSION_STATE_CONDITION_PRE, - BLADE_SESSION_STATE_CONDITION_POST, -} blade_session_state_condition_t; - -typedef enum { - BLADE_SESSION_STATE_NONE, - BLADE_SESSION_STATE_CLEANUP, - BLADE_SESSION_STATE_STARTUP, - BLADE_SESSION_STATE_SHUTDOWN, - BLADE_SESSION_STATE_RUN, -} blade_session_state_t; - -typedef enum { - BLADE_CHANNEL_FLAGS_NONE = 0 << 0, - BLADE_CHANNEL_FLAGS_PUBLIC = 1 << 0, -} blade_channel_flags_t; - - -typedef ks_status_t (*blade_transport_startup_callback_t)(blade_transport_t *bt, config_setting_t *config); -typedef ks_status_t (*blade_transport_shutdown_callback_t)(blade_transport_t *bt); -typedef ks_status_t (*blade_transport_connect_callback_t)(blade_connection_t **bcP, blade_transport_t *bt, blade_identity_t *target, const char *session_id); -typedef ks_status_t (*blade_transport_send_callback_t)(blade_connection_t *bc, cJSON *json); -typedef ks_status_t (*blade_transport_receive_callback_t)(blade_connection_t *bc, cJSON **json); -typedef blade_connection_state_hook_t (*blade_transport_state_callback_t)(blade_connection_t *bc, blade_connection_state_condition_t condition); - -struct blade_transport_callbacks_s { - blade_transport_startup_callback_t onstartup; - blade_transport_shutdown_callback_t onshutdown; - - blade_transport_connect_callback_t onconnect; - - blade_transport_send_callback_t onsend; - blade_transport_receive_callback_t onreceive; - - blade_transport_state_callback_t onstate_startup_inbound; - blade_transport_state_callback_t onstate_startup_outbound; - blade_transport_state_callback_t onstate_shutdown_inbound; - blade_transport_state_callback_t onstate_shutdown_outbound; - blade_transport_state_callback_t onstate_run_inbound; - blade_transport_state_callback_t onstate_run_outbound; -}; - -typedef void (*blade_session_callback_t)(blade_session_t *bs, blade_session_state_condition_t condition, void *data); - - -typedef enum { - BLADE_RPCPUBLISH_COMMAND_NONE, - BLADE_RPCPUBLISH_COMMAND_CONTROLLER_ADD, - BLADE_RPCPUBLISH_COMMAND_CONTROLLER_REMOVE, - BLADE_RPCPUBLISH_COMMAND_CHANNEL_ADD, - BLADE_RPCPUBLISH_COMMAND_CHANNEL_REMOVE, -} blade_rpcpublish_command_t; - -typedef enum { - BLADE_RPCSUBSCRIBE_COMMAND_NONE, - BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_ADD, - BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_REMOVE, -} blade_rpcsubscribe_command_t; - -typedef enum { - BLADE_RPCBROADCAST_COMMAND_NONE, - BLADE_RPCBROADCAST_COMMAND_EVENT, - BLADE_RPCBROADCAST_COMMAND_PROTOCOL_REMOVE, - BLADE_RPCBROADCAST_COMMAND_CHANNEL_REMOVE, -} blade_rpcbroadcast_command_t; - - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/blade_web.h b/libs/libblade/src/include/blade_web.h deleted file mode 100644 index 062259f6ee..0000000000 --- a/libs/libblade/src/include/blade_web.h +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2017, Shane Bryldt - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _BLADE_WEB_H_ -#define _BLADE_WEB_H_ -#include - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) blade_webrequest_create(blade_webrequest_t **bwreqP, const char *action, const char *path); -KS_DECLARE(ks_status_t) blade_webrequest_load(blade_webrequest_t **bwreqP, struct mg_connection *conn); -KS_DECLARE(ks_status_t) blade_webrequest_destroy(blade_webrequest_t **bwreqP); -KS_DECLARE(const char *) blade_webrequest_action_get(blade_webrequest_t *bwreq); -KS_DECLARE(const char *) blade_webrequest_path_get(blade_webrequest_t *bwreq); -KS_DECLARE(ks_status_t) blade_webrequest_query_add(blade_webrequest_t *bwreq, const char *name, const char *value); -KS_DECLARE(const char *) blade_webrequest_query_get(blade_webrequest_t *bwreq, const char *name); -KS_DECLARE(ks_status_t) blade_webrequest_header_add(blade_webrequest_t *bwreq, const char *header, const char *value); -KS_DECLARE(ks_status_t) blade_webrequest_header_printf(blade_webrequest_t *bwreq, const char *header, const char *fmt, ...); -KS_DECLARE(const char *) blade_webrequest_header_get(blade_webrequest_t *bwreq, const char *header); -KS_DECLARE(ks_status_t) blade_webrequest_content_json_append(blade_webrequest_t *bwreq, cJSON *json); -KS_DECLARE(ks_status_t) blade_webrequest_content_string_append(blade_webrequest_t *bwreq, const char *str); -KS_DECLARE(ks_status_t) blade_webrequest_send(blade_webrequest_t *bwreq, ks_bool_t secure, const char *host, ks_port_t port, blade_webresponse_t **bwresP); - -KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_credentials_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char **token); -KS_DECLARE(ks_status_t) blade_webrequest_oauth2_token_by_code_send(ks_bool_t secure, const char *host, ks_port_t port, const char *path, const char *client_id, const char *client_secret, const char *code, const char **token); - - -KS_DECLARE(ks_status_t) blade_webresponse_create(blade_webresponse_t **bwresP, const char *status); -KS_DECLARE(ks_status_t) blade_webresponse_load(blade_webresponse_t **bwresP, struct mg_connection *conn); -KS_DECLARE(ks_status_t) blade_webresponse_destroy(blade_webresponse_t **bwresP); -KS_DECLARE(ks_status_t) blade_webresponse_header_add(blade_webresponse_t *bwres, const char *header, const char *value); -KS_DECLARE(const char *) blade_webresponse_header_get(blade_webresponse_t *bwres, const char *header); -KS_DECLARE(ks_status_t) blade_webresponse_content_json_append(blade_webresponse_t *bwres, cJSON *json); -KS_DECLARE(ks_status_t) blade_webresponse_content_string_append(blade_webresponse_t *bwres, const char *str); -KS_DECLARE(ks_status_t) blade_webresponse_content_json_get(blade_webresponse_t *bwres, cJSON **json); -KS_DECLARE(ks_status_t) blade_webresponse_send(blade_webresponse_t *bwres, struct mg_connection *conn); - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/ks_bencode.h b/libs/libblade/src/include/ks_bencode.h deleted file mode 100644 index 3be2aa3b5a..0000000000 --- a/libs/libblade/src/include/ks_bencode.h +++ /dev/null @@ -1,730 +0,0 @@ -/* - * libbencodetools - * - * Written by Heikki Orsila and - * Janne Kulmala in 2011. - */ - -#ifndef TYPEVALIDATOR_BENCODE_H -#define TYPEVALIDATOR_BENCODE_H - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Used to verify format strings in compile time */ -#ifdef __GNUC__ -#define BEN_CHECK_FORMAT(...) __attribute__ ((format( __VA_ARGS__ ))) -#else -#define BEN_CHECK_FORMAT(...) -#endif - -enum { - BENCODE_BOOL = 1, - BENCODE_DICT, - BENCODE_INT, - BENCODE_LIST, - BENCODE_STR, - BENCODE_USER, -}; - -enum { - BEN_OK = 0, /* No errors. Set to zero. Non-zero implies an error. */ - BEN_INVALID, /* Invalid data was given to decoder */ - BEN_INSUFFICIENT, /* Insufficient amount of data for decoding */ - BEN_NO_MEMORY, /* Memory allocation failed */ - BEN_MISMATCH, /* A given structure did not match unpack format */ -}; - -struct bencode { - char type; -}; - -struct bencode_bool { - char type; - char b; -}; - -struct bencode_dict_node { - long long hash; - struct bencode *key; - struct bencode *value; - size_t next; -}; - -struct bencode_dict { - char type; - char shared; /* non-zero means that the internal data is shared with - other instances and should not be freed */ - size_t n; - size_t alloc; - size_t *buckets; - struct bencode_dict_node *nodes; -}; - -struct bencode_int { - char type; - long long ll; -}; - -struct bencode_list { - char type; - char shared; /* non-zero means that the internal data is shared with - other instances and should not be freed */ - size_t n; - size_t alloc; - struct bencode **values; -}; - -struct bencode_str { - char type; - size_t len; - char *s; -}; - -struct ben_decode_ctx; -struct ben_encode_ctx; - -struct bencode_type { - size_t size; - struct bencode *(*decode) (struct ben_decode_ctx *ctx); - int (*encode) (struct ben_encode_ctx *ctx, const struct bencode *b); - size_t (*get_size) (const struct bencode *b); - void (*freer) (struct bencode *b); - int (*cmp) (const struct bencode *a, const struct bencode *b); -}; - -struct bencode_user { - char type; - struct bencode_type *info; -}; - -struct bencode_error { - int error; /* 0 if no errors */ - int line; /* Error line: 0 is the first line */ - size_t off; /* Error offset in bytes from the start */ -}; - -/* Allocate an instance of a user-defined type */ -void *ben_alloc_user(struct bencode_type *type); - -/* - * Try to set capacity of a list or a dict to 'n' objects. - * The function does nothing if 'n' is less than or equal to the number of - * objects in 'b'. That is, nothing happens if n <= ben_{dict|list}_len(b). - * - * This function is used only for advice. The implementation need not obey it. - * - * The function returns 0 if the new capacity is used, otherwise -1. - * - * Note: This can be used to make construction of lists and dicts - * more efficient when the number of inserted items is known in advance. - */ -int ben_allocate(struct bencode *b, size_t n); - -/* - * Returns an identical but a separate copy of structure b. Returns NULL if - * there is no memory to make a copy. The copy is made recursively. - */ -struct bencode *ben_clone(const struct bencode *b); - -/* - * Returns a weak reference copy of structure b. Only a minimum amount of - * data is copied because the returned structure references to the same - * internal data as the original structure. As a result, the original - * structure must remain valid until the copy is destroyed. - * - * This function is used for optimization for special cases. - */ -struct bencode *ben_shared_clone(const struct bencode *b); - -/* - * ben_cmp() is similar to strcmp(). It compares integers, strings and lists - * similar to Python. User-defined types can be also compared. - * Note: an integer is always less than a string. - * - * ben_cmp(a, b) returns a negative value if "a < b", 0 if "a == b", - * or a positive value if "a > b". - * - * Algorithm for comparing dictionaries is: - * If 'a' and 'b' have different number of keys or keys have different values, - * a non-zero value is returned. Otherwise, they have the exact same keys - * and comparison is done in ben_cmp() order of keys. The value for each key - * is compared, and the first inequal value (ben_cmp() != 0) defines the - * return value of the comparison. - * - * Note: recursive dictionaries in depth have the same issues. - */ -int ben_cmp(const struct bencode *a, const struct bencode *b); - -/* Same as ben_cmp(), but the second argument is a C string */ -int ben_cmp_with_str(const struct bencode *a, const char *s); - -/* - * Comparison function suitable for qsort(). Uses ben_cmp(), so this can be - * used to order both integer and string arrays. - */ -int ben_cmp_qsort(const void *a, const void *b); - -/* - * Decode 'data' with 'len' bytes of data. Returns NULL on error. - * The encoded data must be exactly 'len' bytes (not less), otherwise NULL - * is returned. ben_decode2() function supports partial decoding ('len' is - * larger than actual decoded message) and gives more accurate error reports. - */ -struct bencode *ben_decode(const void *data, size_t len); - -/* - * Same as ben_decode(), but allows one to set start offset for decoding with - * 'off' and reports errors more accurately. - * - * '*off' must point to decoding start offset inside 'data'. - * If decoding is successful, '*off' is updated to point to the next byte - * after the decoded message. - * - * If 'error != NULL', it is updated according to the success and error of - * the decoding. BEN_OK is success, BEN_INVALID means invalid data. - * BEN_INSUFFICIENT means data is invalid but could be valid if more data - * was given for decoding. BEN_NO_MEMORY means decoding ran out of memory. - */ -struct bencode *ben_decode2(const void *data, size_t len, size_t *off, int *error); - -/* - * Same as ben_decode2(), but allows one to define user types. - */ -struct bencode *ben_decode3(const void *data, size_t len, size_t *off, int *error, struct bencode_type *types[128]); - -/* - * Same as ben_decode(), but decodes data encoded with ben_print(). This is - * whitespace tolerant, so intended Python syntax can also be read. - * The decoder skips comments that begin with a '#' character. - * The comment starts from '#' character and ends at the end of the same line. - * - * For example, this can be used to read in config files written as a Python - * dictionary. - * - * ben_decode_printed2() fills information about the error in - * struct bencode_error. - * error->error is 0 on success, otherwise it is an error code - * (see ben_decode2()). - * error->line is the line number where error occured. - * error->off is the byte offset of error (approximation). - */ -struct bencode *ben_decode_printed(const void *data, size_t len); -struct bencode *ben_decode_printed2(const void *data, size_t len, size_t *off, struct bencode_error *error); - -/* Get the serialization size of bencode structure 'b' */ -size_t ben_encoded_size(const struct bencode *b); - -/* encode 'b'. Return encoded data with a pointer, and length in '*len' */ -void *ben_encode(size_t *len, const struct bencode *b); - -/* - * encode 'b' into 'data' buffer with at most 'maxlen' bytes. - * Returns the size of encoded data. - */ -size_t ben_encode2(char *data, size_t maxlen, const struct bencode *b); - -/* - * You must use ben_free() for all allocated bencode structures after use. - * If b == NULL, ben_free does nothing. - * - * ben_free() frees all the objects contained within the bencoded structure. - * It recursively iterates over lists and dictionaries and frees objects. - */ -void ben_free(struct bencode *b); - -long long ben_str_hash(const struct bencode *b); -long long ben_int_hash(const struct bencode *b); -long long ben_hash(const struct bencode *b); - -/* Create a string from binary data with len bytes */ -struct bencode *ben_blob(const void *data, size_t len); - -/* Create a boolean from integer */ -struct bencode *ben_bool(int b); - -/* Create an empty dictionary */ -struct bencode *ben_dict(void); - -/* - * Try to locate 'key' in dictionary. Returns the associated value, if found. - * Returns NULL if the key does not exist. - */ -struct bencode *ben_dict_get(const struct bencode *d, const struct bencode *key); - -struct bencode *ben_dict_get_by_str(const struct bencode *d, const char *key); -struct bencode *ben_dict_get_by_int(const struct bencode *d, long long key); - -struct bencode_keyvalue { - struct bencode *key; - struct bencode *value; -}; - -/* - * Returns an array of key-value pairs in key order as defined by ben_cmp(). - * Array elements are struct bencode_keyvalue members. Returns NULL if - * the array can not be allocated or the bencode object is not a dictionary. - * The returned array must be freed by using free(). The length of the - * array can be determined with ben_dict_len(d). - * - * Warning: key and value pointers in the array are pointers to exact same - * objects in the dictionary. Therefore, the dictionary and its key-values - * must exist while the same keys and values are accessed from the array. - */ -struct bencode_keyvalue *ben_dict_ordered_items(const struct bencode *d); - -/* - * Try to locate 'key' in dictionary. Returns the associated value, if found. - * The value must be later freed with ben_free(). Returns NULL if the key - * does not exist. - */ -struct bencode *ben_dict_pop(struct bencode *d, const struct bencode *key); - -struct bencode *ben_dict_pop_by_str(struct bencode *d, const char *key); -struct bencode *ben_dict_pop_by_int(struct bencode *d, long long key); - -/* - * Set 'key' in dictionary to be 'value'. An old value exists for the key - * is freed if it exists. 'key' and 'value' are owned by the dictionary - * after a successful call (one may not call ben_free() for 'key' or - * 'value'). One may free 'key' and 'value' if the call is unsuccessful. - * - * Returns 0 on success, -1 on failure (no memory). - */ -int ben_dict_set(struct bencode *d, struct bencode *key, struct bencode *value); - -/* Same as ben_dict_set(), but the key is a C string */ -int ben_dict_set_by_str(struct bencode *d, const char *key, struct bencode *value); - -/* Same as ben_dict_set(), but the key and value are C strings */ -int ben_dict_set_str_by_str(struct bencode *d, const char *key, const char *value); - -struct bencode *ben_int(long long ll); - -/* Create an empty list */ -struct bencode *ben_list(void); - -/* - * Append 'b' to 'list'. Returns 0 on success, -1 on failure (no memory). - * One may not call ben_free(b) after a successful call, because the list owns - * the object 'b'. - */ -int ben_list_append(struct bencode *list, struct bencode *b); - -int ben_list_append_str(struct bencode *list, const char *s); -int ben_list_append_int(struct bencode *list, long long ll); - -/* Remove and return value at position 'pos' in list */ -struct bencode *ben_list_pop(struct bencode *list, size_t pos); - -/* - * Returns a Python formatted C string representation of 'b' on success, - * NULL on failure. The returned string should be freed with free(). - * - * Note: The string is terminated with '\0'. All instances of '\0' bytes in - * the bencoded data are escaped so that there is only one '\0' byte - * in the generated string at the end. - */ -char *ben_print(const struct bencode *b); - -/* Create a string from C string (note bencode string may contain '\0'. */ -struct bencode *ben_str(const char *s); - -/* Return a human readable explanation of error returned with ben_decode2() */ -const char *ben_strerror(int error); - -/* - * Unpack a Bencoded structure similar to scanf(). Takes a format string and - * a list of pointers as variable arguments. The given b structure is checked - * against the format and values are unpacked using the given specifiers. - * A specifier begins with a percent (%) that follows a string of specifier - * characters documented below. - * The syntax is similar to Python format for recursive data structures, and - * consists of tokens {, }, [, ] with any number of spaces between them. - * The keys of a dictionary are given as literal strings or integers and - * matched against the keys of the Bencoded structure. - * - * Unpack modifiers: - * l The integer is of type long or unsigned long, and the type of the - * argument is expected to be long * or unsigned long *. - * ll The integer is a long long or an unsigned long long, and the - * argument is long long * or unsigned long long *. - * L Same as ll. - * q Same as ll. - * - * Unpack specifiers: - * %ps The Bencode value must be a string and a pointer to a string - * (char **) is expected to be given as arguments. Note, returns a - * reference to the internal string buffer. The returned memory should - * not be freed and it has the same life time as the Bencode string. - * - * %pb Takes any structure and writes a pointer given as an argument. - * The argument is expected to be "struct bencode **". Note, returns a - * reference to the value inside the structure passed to ben_unpack(). - * The returned memory should not be freed and it has the same life - * time as the original structure. - * - * %d The bencode value is expected to be a (signed) integer. The - * preceeding conversion modifiers define the type of the given - * pointer. - - * %u The bencode value is expected to be an unsigned integer. The - * preceeding conversion modifiers define the type of the given - * pointer. - */ -int ben_unpack(const struct bencode *b, const char *fmt, ...) - BEN_CHECK_FORMAT(scanf, 2, 3); - -int ben_unpack2(const struct bencode *b, size_t *off, struct bencode_error *error, const char *fmt, ...) - BEN_CHECK_FORMAT(scanf, 4, 5); - -/* - * Pack a Bencoded structure similar to printf(). Takes a format string and - * a list of values as variable arguments. - * Works similarly to ben_decode_printed(), but allows the string to values - * specifiers which are replaced with values given as arguments. - * A specifier begins with a percent (%) that follows a string of specifier - * characters documented below. - * - * Value modifiers: - * l The integer is of type long or unsigned long. - * ll The integer is a long long or an unsigned long long. - * L Same as ll. - * q Same as ll. - * - * Value specifiers: - * %s A string pointer (char *) expected to be given as argument. A new - * Bencode string is constructed from the given string. - * - * %pb A Bencode structure (struct bencode *) is expected to be given as - * argument. Note, takes ownership of the structure, even when an - * error is returned. - * - * %d Constructs a new integer from the given (signed) integer. The - * preceeding conversion modifiers define the type of the value. - * - * %u Constructs a new integer from the given unsigned integer. The - * preceeding conversion modifiers define the type of the value. - */ -struct bencode *ben_pack(const char *fmt, ...) - BEN_CHECK_FORMAT(printf, 1, 2); - -/* ben_is_bool() returns 1 iff b is a boolean, 0 otherwise */ -static inline int ben_is_bool(const struct bencode *b) -{ - return b->type == BENCODE_BOOL; -} -static inline int ben_is_dict(const struct bencode *b) -{ - return b->type == BENCODE_DICT; -} -static inline int ben_is_int(const struct bencode *b) -{ - return b->type == BENCODE_INT; -} -static inline int ben_is_list(const struct bencode *b) -{ - return b->type == BENCODE_LIST; -} -static inline int ben_is_str(const struct bencode *b) -{ - return b->type == BENCODE_STR; -} -static inline int ben_is_user(const struct bencode *b) -{ - return b->type == BENCODE_USER; -} - -/* - * ben_bool_const_cast(b) returns "(const struct bencode_bool *) b" if the - * underlying object is a boolean, NULL otherwise. - */ -static inline const struct bencode_bool *ben_bool_const_cast(const struct bencode *b) -{ - return b->type == BENCODE_BOOL ? ((const struct bencode_bool *) b) : NULL; -} - -/* - * ben_bool_cast(b) returns "(struct bencode_bool *) b" if the - * underlying object is a boolean, NULL otherwise. - */ -static inline struct bencode_bool *ben_bool_cast(struct bencode *b) -{ - return b->type == BENCODE_BOOL ? ((struct bencode_bool *) b) : NULL; -} - -static inline const struct bencode_dict *ben_dict_const_cast(const struct bencode *b) -{ - return b->type == BENCODE_DICT ? ((const struct bencode_dict *) b) : NULL; -} -static inline struct bencode_dict *ben_dict_cast(struct bencode *b) -{ - return b->type == BENCODE_DICT ? ((struct bencode_dict *) b) : NULL; -} - -static inline const struct bencode_int *ben_int_const_cast(const struct bencode *i) -{ - return i->type == BENCODE_INT ? ((const struct bencode_int *) i) : NULL; -} -static inline struct bencode_int *ben_int_cast(struct bencode *i) -{ - return i->type == BENCODE_INT ? ((struct bencode_int *) i) : NULL; -} - -static inline const struct bencode_list *ben_list_const_cast(const struct bencode *list) -{ - return list->type == BENCODE_LIST ? ((const struct bencode_list *) list) : NULL; -} -static inline struct bencode_list *ben_list_cast(struct bencode *list) -{ - return list->type == BENCODE_LIST ? ((struct bencode_list *) list) : NULL; -} - -static inline const struct bencode_str *ben_str_const_cast(const struct bencode *str) -{ - return str->type == BENCODE_STR ? ((const struct bencode_str *) str) : NULL; -} -static inline struct bencode_str *ben_str_cast(struct bencode *str) -{ - return str->type == BENCODE_STR ? ((struct bencode_str *) str) : NULL; -} - -static inline const struct bencode_user *ben_user_const_cast(const struct bencode *user) -{ - return user->type == BENCODE_USER ? ((const struct bencode_user *) user) : NULL; -} -static inline struct bencode_user *ben_user_cast(struct bencode *user) -{ - return user->type == BENCODE_USER ? ((struct bencode_user *) user) : NULL; -} - -static inline int ben_is_user_type(const struct bencode *b, struct bencode_type *type) -{ - return b->type == BENCODE_USER ? ((const struct bencode_user *) b)->info == type : 0; -} - -static inline const void *ben_user_type_const_cast(const struct bencode *b, struct bencode_type *type) -{ - return (b->type == BENCODE_USER && ((const struct bencode_user *) b)->info == type) ? b : NULL; -} -static inline void *ben_user_type_cast(struct bencode *b, struct bencode_type *type) -{ - return (b->type == BENCODE_USER && ((const struct bencode_user *) b)->info == type) ? b : NULL; -} - -/* Return the number of keys in a dictionary 'b' */ -static inline size_t ben_dict_len(const struct bencode *b) -{ - return ben_dict_const_cast(b)->n; -} - -/* Return the number of items in a list 'b' */ -static inline size_t ben_list_len(const struct bencode *b) -{ - return ben_list_const_cast(b)->n; -} - -/* ben_list_get(list, i) returns object at position i in list */ -static inline struct bencode *ben_list_get(const struct bencode *list, size_t i) -{ - const struct bencode_list *l = ben_list_const_cast(list); - if (i >= l->n) { - fprintf(stderr, "bencode: List index out of bounds\n"); - abort(); - } - return l->values[i]; -} - -/* - * ben_list_set(list, i, b) sets object b to list at position i. - * The old value at position i is freed. - * The program aborts if position i is out of bounds. - */ -void ben_list_set(struct bencode *list, size_t i, struct bencode *b); - -/* Return the number of bytes in a string 'b' */ -static inline size_t ben_str_len(const struct bencode *b) -{ - return ben_str_const_cast(b)->len; -} - -/* Return boolean value (0 or 1) of 'b' */ -static inline int ben_bool_val(const struct bencode *b) -{ - return ben_bool_const_cast(b)->b ? 1 : 0; -} - -/* Return integer value of 'b' */ -static inline long long ben_int_val(const struct bencode *b) -{ - return ben_int_const_cast(b)->ll; -} - -/* - * Note: the string is always zero terminated. Also, the string may - * contain more than one zero. - * bencode strings are not compatible with C strings. - */ -static inline const char *ben_str_val(const struct bencode *b) -{ - return ben_str_const_cast(b)->s; -} - -/* - * ben_list_for_each() is an iterator macro for bencoded lists. - * - * Note, it is not allowed to change the list while iterating except by - * using ben_list_pop_current(). - * - * pos is a size_t. - * - * Example: - * - * size_t pos; - * struct bencode *list = xxx; - * struct bencode *value; - * ben_list_for_each(value, pos, list) { - * inspect(value); - * } - */ -#define ben_list_for_each(value, pos, l) \ - for ((pos) = (size_t) 0; \ - (pos) < (ben_list_const_cast(l))->n && \ - ((value) = ((const struct bencode_list *) (l))->values[(pos)]) != NULL ; \ - (pos)++) - -/* - * ben_list_pop_current() returns and removes the current item at 'pos' - * while iterating the list with ben_list_for_each(). - * It can be used more than once per walk, but only once per item. - * Example below: - * - * Filter out all items from list whose string value does not begin with "foo". - * - * ben_list_for_each(value, pos, list) { - * if (strncmp(ben_str_val(value), "foo", 3) != 0) - * ben_free(ben_list_pop_current(&pos, list)); - * } - */ -static inline struct bencode *ben_list_pop_current(struct bencode *list, - size_t *pos) -{ - struct bencode *value = ben_list_pop(list, *pos); - (*pos)--; - return value; -} - -/* - * ben_dict_for_each() is an iterator macro for bencoded dictionaries. - * - * Note, it is not allowed to change the dictionary while iterating except - * by using ben_dict_pop_current(). - * - * struct bencode *dict = ben_dict(); - * size_t pos; - * struct bencode *key; - * struct bencode *value; - * ben_dict_set_str_by_str(dict, "foo", "bar"); - * - * ben_dict_for_each(key, value, pos, dict) { - * use(key, value); - * } - * - * pos is a size_t. - */ -#define ben_dict_for_each(bkey, bvalue, pos, d) \ - for ((pos) = 0; \ - (pos) < (ben_dict_const_cast(d))->n && \ - ((bkey) = ((const struct bencode_dict *) (d))->nodes[(pos)].key) != NULL && \ - ((bvalue) = ((const struct bencode_dict *) (d))->nodes[(pos)].value) != NULL; \ - (pos)++) - -/* - * ben_dict_pop_current() deletes the current item at 'pos' while iterating - * the dictionary with ben_dict_for_each(). It can be used more than once - * per walk, but only once per item. Example below: - * - * Filter out all items from dictionary whose key does not begin with "foo". - * - * ben_dict_for_each(key, value, pos, dict) { - * if (strncmp(ben_str_val(key), "foo", 3) != 0) - * ben_free(ben_dict_pop_current(dict, &pos)); - * } - */ -struct bencode *ben_dict_pop_current(struct bencode *dict, size_t *pos); - -/* Report an error while decoding. Returns NULL. */ -void *ben_insufficient_ptr(struct ben_decode_ctx *ctx); -void *ben_invalid_ptr(struct ben_decode_ctx *ctx); -void *ben_oom_ptr(struct ben_decode_ctx *ctx); - -/* - * Decode from the current position of 'ctx'. - * - * This function is used to implement decoders for user-defined types. - */ -struct bencode *ben_ctx_decode(struct ben_decode_ctx *ctx); - -/* - * Test whether the input of 'ctx' has at least n bytes left. - * Returns 0 when there is enough bytes left and -1 when there isn't. - * - * This function is used to implement decoders for user-defined types. - */ -int ben_need_bytes(const struct ben_decode_ctx *ctx, size_t n); - -/* - * Returns the character in current position of 'ctx'. - * - * This function is used to implement decoders for user-defined types. - */ -char ben_current_char(const struct ben_decode_ctx *ctx); - -/* - * Get the next n bytes from input. - * Returns pointer to the data or NULL when there aren't enough bytes left. - * - * This function is used to implement decoders for user-defined types. - */ -const char *ben_current_buf(const struct ben_decode_ctx *ctx, size_t n); - -/* - * Increments current position by n. - * - * This function is used to implement decoders for user-defined types. - */ -void ben_skip(struct ben_decode_ctx *ctx, size_t n); - -/* - * Encode to the output of 'ctx'. The size of the encoded data can be obtained - * with ben_encoded_size(). - * - * This function is used to implement encoders for user-defined types. - */ -int ben_ctx_encode(struct ben_encode_ctx *ctx, const struct bencode *b); - -/* - * Append one character to output of 'ctx'. The amount of bytes written to the - * output must be the same as returned by get_size(). - * - * This function is used to implement encoders for user-defined types. - */ -int ben_put_char(struct ben_encode_ctx *ctx, char c); - -/* - * Append data to output of 'ctx'. The amount of bytes written to the output - * must be the same as returned by get_size(). - * - * This function is used to implement encoders for user-defined types. - */ -int ben_put_buffer(struct ben_encode_ctx *ctx, const void *buf, size_t len); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/libblade/src/include/ks_dht-int.h b/libs/libblade/src/include/ks_dht-int.h deleted file mode 100644 index ad5d20bb9c..0000000000 --- a/libs/libblade/src/include/ks_dht-int.h +++ /dev/null @@ -1,447 +0,0 @@ -#ifndef KS_DHT_INT_H -#define KS_DHT_INT_H - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -/** - * Determines the appropriate endpoint to reach a remote address. - * If an endpoint is provided, nothing more needs to be done. - * If no endpoint is provided, first it will check for an active endpoint it can route though. - * If no active endpoint is available and autorouting is enabled it will attempt to bind a usable endpoint. - * @param dht pointer to the dht instance - * @param raddr pointer to the remote address - * @param endpoint dereferenced in/out pointer to the endpoint, if populated then returns immediately - * @return The ks_status_t result: KS_STATUS_SUCCESS, ... - * @see ks_ip_route - * @see ks_hash_read_unlock - * @see ks_addr_set - * @see ks_dht_bind - */ -KS_DECLARE(ks_status_t) ks_dht_autoroute_check(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_endpoint_t **endpoint); - -/** - * Called internally to receive datagrams from endpoints. - * Handles datagrams by dispatching each through a threadpool. - * @param dht pointer to the dht instance - * @param timeout time in ms to wait for an incoming datagram on any endpoint - */ -KS_DECLARE(void) ks_dht_pulse_endpoints(ks_dht_t *dht, int32_t timeout); - -/** - * Called internally to expire or reannounce storage item data. - * Handles reannouncing and purging of expiring storage items. - * @param dht pointer to the dht instance - */ -KS_DECLARE(void) ks_dht_pulse_storageitems(ks_dht_t *dht); - -/** - * Called internally to process job state machine. - * Handles completing and purging of finished jobs. - * @param dht pointer to the dht instance - */ -KS_DECLARE(void) ks_dht_pulse_jobs(ks_dht_t *dht); - -/** - * Called internally to send queued messages. - * Handles throttling of message sending to ensure system buffers are not overloaded and messages are not dropped. - * @param dht pointer to the dht instance - */ -KS_DECLARE(void) ks_dht_pulse_send(ks_dht_t *dht); - -/** - * Called internally to expire transactions. - * Handles purging of expired and finished transactions. - * @param dht pointer to the dht instance - */ -KS_DECLARE(void) ks_dht_pulse_transactions(ks_dht_t *dht); - -/** - * Called internally to expire and cycle tokens. - * Handles cycling new secret entropy for token generation. - * @param dht pointer to the dht instance - */ -KS_DECLARE(void) ks_dht_pulse_tokens(ks_dht_t *dht); - -/** - * Converts a ks_dht_nodeid_t into it's hex string representation. - * @param id pointer to the nodeid - * @param buffer pointer to the buffer able to contain at least (KS_DHT_NODEID_SIZE * 2) + 1 characters - * @return The pointer to the front of the populated string buffer - */ -KS_DECLARE(char *) ks_dht_hex(const uint8_t *data, char *buffer, ks_size_t len); - -/** - * Compacts address information as per the DHT specifications. - * @param address pointer to the address being compacted from - * @param buffer pointer to the buffer containing compacted data - * @param buffer_length pointer to the buffer length consumed - * @param buffer_size max size of the buffer - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_NO_MEM - */ -KS_DECLARE(ks_status_t) ks_dht_utility_compact_addressinfo(const ks_sockaddr_t *address, - uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size); - -/** - * Expands address information as per the DHT specifications. - * @param buffer pointer to the buffer containing compacted data - * @param buffer_length pointer to the buffer length consumed - * @param buffer_size max size of the buffer - * @param address pointer to the address being expanded into - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_NO_MEM, ... - * @see ks_addr_set_raw - */ -KS_DECLARE(ks_status_t) ks_dht_utility_expand_addressinfo(const uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size, - ks_sockaddr_t *address); - -/** - * Compacts node information as per the DHT specifications. - * Compacts address information after the nodeid. - * @param nodeid pointer to the nodeid being compacted from - * @param address pointer to the address being compacted from - * @param buffer pointer to the buffer containing compacted data - * @param buffer_length pointer to the buffer length consumed - * @param buffer_size max size of the buffer - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_NO_MEM, ... - * @see ks_dht_utility_compact_addressinfo - */ -KS_DECLARE(ks_status_t) ks_dht_utility_compact_nodeinfo(const ks_dht_nodeid_t *nodeid, - const ks_sockaddr_t *address, - uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size); - -/** - * Expands address information as per the DHT specifications. - * Expands compacted address information after the nodeid. - * @param buffer pointer to the buffer containing compacted data - * @param buffer_length pointer to the buffer length consumed - * @param buffer_size max size of the buffer - * @param address pointer to the address being expanded into - * @param nodeid pointer to the nodeid being expanded into - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_NO_MEM, ... - * @see ks_dht_utility_expand_addressinfo - */ -KS_DECLARE(ks_status_t) ks_dht_utility_expand_nodeinfo(const uint8_t *buffer, - ks_size_t *buffer_length, - ks_size_t buffer_size, - ks_dht_nodeid_t *nodeid, - ks_sockaddr_t *address); - -/** - * Extracts a ks_dht_nodeid_t from a bencode dictionary given a string key. - * @param args pointer to the bencode dictionary - * @param key string key in the bencode dictionary to extract the value from - * @param nodeid dereferenced out pointer to the nodeid - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_ARG_INVALID - */ -KS_DECLARE(ks_status_t) ks_dht_utility_extract_nodeid(struct bencode *args, const char *key, ks_dht_nodeid_t **nodeid); - -/** - * Extracts a ks_dht_token_t from a bencode dictionary given a string key. - * @param args pointer to the bencode dictionary - * @param key string key in the bencode dictionary to extract the value from - * @param nodeid dereferenced out pointer to the token - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_ARG_INVALID - */ -KS_DECLARE(ks_status_t) ks_dht_utility_extract_token(struct bencode *args, const char *key, ks_dht_token_t **token); - -/** - * Generates an opaque write token based on a shifting secret value, the remote address and target nodeid of interest. - * This token ensures that future operations can be verified to the remote peer and target id requested. - * @param secret rotating secret portion of the token hash - * @param raddr pointer to the remote address used for the ip and port in the token hash - * @param target pointer to the nodeid of the target used for the token hash - * @param token pointer to the output token being generated - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_FAIL - */ -KS_DECLARE(ks_status_t) ks_dht_token_generate(uint32_t secret, const ks_sockaddr_t *raddr, ks_dht_nodeid_t *target, ks_dht_token_t *token); - -/** - * Verify an opaque write token matches the provided remote address and target nodeid. - * Handles checking against the last two secret values for the token hash. - * @param dht pointer to the dht instance - * @param raddr pointer to the remote address used for the ip and port in the token hash - * @param target pointer to the nodeid of the target used for the token hash - * @param token pointer to the input token being compared - * @return Either KS_TRUE if verification passes, otherwise KS_FALSE - */ -KS_DECLARE(ks_bool_t) ks_dht_token_verify(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_nodeid_t *target, ks_dht_token_t *token); - -/** - * Encodes a message for transmission as a UDP datagram and sends it. - * Uses the internally tracked local endpoint and remote address to route the UDP datagram. - * @param dht pointer to the dht instance - * @param message pointer to the message being sent - * @return The ks_status_t result: KS_STATUS_SUCCESS, ... - * @see ks_socket_sendto - */ -KS_DECLARE(ks_status_t) ks_dht_send(ks_dht_t *dht, ks_dht_message_t *message); - -/** - * Sets up the common parts of a query message. - * Determines the local endpoint aware of autorouting, assigns the remote address, generates a transaction, and queues a callback. - * @param dht pointer to the dht instance - * @param job pointer to the job - * @param query string value of the query type, for example "ping" - * @param callback callback to be called when response to transaction is received - * @param transaction dereferenced out pointer to the allocated transaction, may be NULL to ignore output - * @param message dereferenced out pointer to the allocated message - * @param args dereferenced out pointer to the allocated bencode args, may be NULL to ignore output - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_FAIL, ... - * @see ks_dht_autoroute_check - * @see ks_dht_transaction_alloc - * @see ks_dht_transaction_init - * @see ks_dht_message_alloc - * @see ks_dht_message_init - * @see ks_dht_message_query - * @see ks_hash_insert - */ -KS_DECLARE(ks_status_t) ks_dht_query_setup(ks_dht_t *dht, - ks_dht_job_t *job, - const char *query, - ks_dht_job_callback_t callback, - ks_dht_transaction_t **transaction, - ks_dht_message_t **message, - struct bencode **args); - -/** - * Sets up the common parts of a response message. - * Determines the local endpoint aware of autorouting, assigns the remote address, and assigns the transaction. - * @param dht pointer to the dht instance - * @param ep pointer to the endpoint, may be NULL to find an endpoint or autoroute one - * @param raddr pointer to the remote address - * @param transactionid pointer to the buffer containing the transactionid, may be of variable size depending on the querying node - * @param transactionid_length length of the transactionid buffer - * @param message dereferenced out pointer to the allocated message - * @param args dereferenced out pointer to the allocated bencode args, may be NULL to ignore output - * @return The ks_status_t result: KS_STATUS_SUCCESS, ... - * @see ks_dht_autoroute_check - * @see ks_dht_message_alloc - * @see ks_dht_message_init - * @see ks_dht_message_response - */ -KS_DECLARE(ks_status_t) ks_dht_response_setup(ks_dht_t *dht, - ks_dht_endpoint_t *ep, - const ks_sockaddr_t *raddr, - uint8_t *transactionid, - ks_size_t transactionid_length, - ks_dht_message_t **message, - struct bencode **args); - - -KS_DECLARE(ks_status_t) ks_dht_error(ks_dht_t *dht, - ks_dht_endpoint_t *ep, - const ks_sockaddr_t *raddr, - uint8_t *transactionid, - ks_size_t transactionid_length, - long long errorcode, - const char *errorstr); - -KS_DECLARE(void) ks_dht_pulse_jobs(ks_dht_t *dht); -KS_DECLARE(ks_status_t) ks_dht_query_ping(ks_dht_t *dht, ks_dht_job_t *job); -KS_DECLARE(ks_status_t) ks_dht_query_findnode(ks_dht_t *dht, ks_dht_job_t *job); -KS_DECLARE(ks_status_t) ks_dht_query_get(ks_dht_t *dht, ks_dht_job_t *job); -KS_DECLARE(ks_status_t) ks_dht_query_put(ks_dht_t *dht, ks_dht_job_t *job); - -KS_DECLARE(void *)ks_dht_process(ks_thread_t *thread, void *data); - -KS_DECLARE(ks_status_t) ks_dht_process_query(ks_dht_t *dht, ks_dht_message_t *message); -KS_DECLARE(ks_status_t) ks_dht_process_response(ks_dht_t *dht, ks_dht_message_t *message); -KS_DECLARE(ks_status_t) ks_dht_process_error(ks_dht_t *dht, ks_dht_message_t *message); - -KS_DECLARE(ks_status_t) ks_dht_process_query_ping(ks_dht_t *dht, ks_dht_message_t *message); -KS_DECLARE(ks_status_t) ks_dht_process_response_ping(ks_dht_t *dht, ks_dht_job_t *job); - -KS_DECLARE(ks_status_t) ks_dht_process_query_findnode(ks_dht_t *dht, ks_dht_message_t *message); -KS_DECLARE(ks_status_t) ks_dht_process_response_findnode(ks_dht_t *dht, ks_dht_job_t *job); - -KS_DECLARE(ks_status_t) ks_dht_process_query_get(ks_dht_t *dht, ks_dht_message_t *message); -KS_DECLARE(ks_status_t) ks_dht_process_response_get(ks_dht_t *dht, ks_dht_job_t *job); - -KS_DECLARE(ks_status_t) ks_dht_process_query_put(ks_dht_t *dht, ks_dht_message_t *message); -KS_DECLARE(ks_status_t) ks_dht_process_response_put(ks_dht_t *dht, ks_dht_job_t *job); - - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_datagram_create(ks_dht_datagram_t **datagram, - ks_pool_t *pool, - ks_dht_t *dht, - ks_dht_endpoint_t *endpoint, - const ks_sockaddr_t *raddr); -KS_DECLARE(void) ks_dht_datagram_destroy(ks_dht_datagram_t **datagram); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_job_create(ks_dht_job_t **job, - ks_pool_t *pool, - const ks_sockaddr_t *raddr, - int32_t attempts, - void *data); -KS_DECLARE(void) ks_dht_job_build_ping(ks_dht_job_t *job, ks_dht_job_callback_t query_callback, ks_dht_job_callback_t finish_callback); -KS_DECLARE(void) ks_dht_job_build_findnode(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback, - ks_dht_nodeid_t *target); -KS_DECLARE(void) ks_dht_job_build_get(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback, - ks_dht_nodeid_t *target, - const uint8_t *salt, - ks_size_t salt_length); -KS_DECLARE(void) ks_dht_job_build_put(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback, - ks_dht_token_t *token, - int64_t cas, - ks_dht_storageitem_t *item); -KS_DECLARE(void) ks_dht_job_build_search(ks_dht_job_t *job, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback); -KS_DECLARE(void) ks_dht_job_build_search_findnode(ks_dht_job_t *job, - ks_dht_nodeid_t *target, - uint32_t family, - ks_dht_job_callback_t query_callback, - ks_dht_job_callback_t finish_callback); -KS_DECLARE(void) ks_dht_job_destroy(ks_dht_job_t **job); - - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_endpoint_create(ks_dht_endpoint_t **endpoint, - ks_pool_t *pool, - const ks_sockaddr_t *addr, - ks_socket_t sock); -KS_DECLARE(void) ks_dht_endpoint_destroy(ks_dht_endpoint_t **endpoint); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_message_create(ks_dht_message_t **message, - ks_pool_t *pool, - ks_dht_endpoint_t *endpoint, - const ks_sockaddr_t *raddr, - ks_bool_t alloc_data); -/** - * - */ -KS_DECLARE(void) ks_dht_message_destroy(ks_dht_message_t **message); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_message_parse(ks_dht_message_t *message, const uint8_t *buffer, ks_size_t buffer_length); - - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_search_create(ks_dht_search_t **search, - ks_pool_t *pool, - ks_dhtrt_routetable_t *table, - const ks_dht_nodeid_t *target, - ks_dht_job_callback_t callback, - void *data); -KS_DECLARE(void) ks_dht_search_destroy(ks_dht_search_t **search); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_publish_create(ks_dht_publish_t **publish, - ks_pool_t *pool, - ks_dht_job_callback_t callback, - void *data, - int64_t cas, - ks_dht_storageitem_t *item); -KS_DECLARE(void) ks_dht_publish_destroy(ks_dht_publish_t **publish); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_distribute_create(ks_dht_distribute_t **distribute, - ks_pool_t *pool, - ks_dht_storageitem_callback_t callback, - void *data, - int64_t cas, - ks_dht_storageitem_t *item); -KS_DECLARE(void) ks_dht_distribute_destroy(ks_dht_distribute_t **distribute); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_immutable_internal(struct bencode *value, ks_dht_nodeid_t *target); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_mutable_internal(ks_dht_storageitem_pkey_t *pk, struct bencode *salt, ks_dht_nodeid_t *target); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_immutable_internal(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - struct bencode *v, - ks_bool_t clone_v); -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_immutable(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - const uint8_t *value, - ks_size_t value_length); -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_mutable_internal(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - struct bencode *v, - ks_bool_t clone_v, - ks_dht_storageitem_pkey_t *pk, - struct bencode *salt, - ks_bool_t clone_salt, - int64_t sequence, - ks_dht_storageitem_signature_t *signature); -KS_DECLARE(ks_status_t) ks_dht_storageitem_create_mutable(ks_dht_storageitem_t **item, - ks_pool_t *pool, - ks_dht_nodeid_t *target, - const uint8_t *value, - ks_size_t value_length, - ks_dht_storageitem_pkey_t *pk, - const uint8_t *salt, - ks_size_t salt_length, - int64_t sequence, - ks_dht_storageitem_signature_t *signature); -KS_DECLARE(void) ks_dht_storageitem_update_mutable(ks_dht_storageitem_t *item, struct bencode *v, int64_t sequence, ks_dht_storageitem_signature_t *signature); -KS_DECLARE(void) ks_dht_storageitem_destroy(ks_dht_storageitem_t **item); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_transaction_create(ks_dht_transaction_t **transaction, - ks_pool_t *pool, - ks_dht_job_t *job, - uint32_t transactionid, - ks_dht_job_callback_t callback); -KS_DECLARE(void) ks_dht_transaction_destroy(ks_dht_transaction_t **transaction); - -KS_END_EXTERN_C - -#endif /* KS_DHT_INT_H */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/ks_dht.h b/libs/libblade/src/include/ks_dht.h deleted file mode 100644 index 2c84921a87..0000000000 --- a/libs/libblade/src/include/ks_dht.h +++ /dev/null @@ -1,596 +0,0 @@ -#ifndef KS_DHT_H -#define KS_DHT_H - -#include "ks.h" -#include "ks_bencode.h" -#include "sodium.h" - -KS_BEGIN_EXTERN_C - - -#define KS_DHT_DEFAULT_PORT 5309 - -#define KS_DHT_TPOOL_MIN 2 -#define KS_DHT_TPOOL_MAX 8 -#define KS_DHT_TPOOL_STACK (1024 * 256) -#define KS_DHT_TPOOL_IDLE 10 - -#define KS_DHT_DATAGRAM_BUFFER_SIZE 1000 - -//#define KS_DHT_RECV_BUFFER_SIZE 0xFFFF - -#define KS_DHT_NODEID_SIZE 20 - -#define KS_DHT_RESPONSE_NODES_MAX_SIZE 8 - -#define KS_DHT_MESSAGE_TRANSACTIONID_MAX_SIZE 20 -#define KS_DHT_MESSAGE_TYPE_MAX_SIZE 20 -#define KS_DHT_MESSAGE_QUERY_MAX_SIZE 20 -#define KS_DHT_MESSAGE_ERROR_MAX_SIZE 256 - -#define KS_DHT_TRANSACTION_EXPIRATION 10 -#define KS_DHT_TRANSACTIONS_PULSE 1 - -#define KS_DHT_SEARCH_RESULTS_MAX_SIZE 8 // @todo replace with KS_DHTRT_BUCKET_SIZE - -#define KS_DHT_STORAGEITEM_PKEY_SIZE crypto_sign_PUBLICKEYBYTES -#define KS_DHT_STORAGEITEM_SKEY_SIZE crypto_sign_SECRETKEYBYTES -#define KS_DHT_STORAGEITEM_SALT_MAX_SIZE 64 -#define KS_DHT_STORAGEITEM_SIGNATURE_SIZE crypto_sign_BYTES -#define KS_DHT_STORAGEITEM_EXPIRATION 7200 -#define KS_DHT_STORAGEITEM_KEEPALIVE 300 -#define KS_DHT_STORAGEITEMS_PULSE 10 - -#define KS_DHT_TOKEN_SIZE SHA_DIGEST_LENGTH -#define KS_DHT_TOKEN_EXPIRATION 300 -#define KS_DHT_TOKENS_PULSE 1 - -#define KS_DHTRT_MAXQUERYSIZE 20 - -typedef struct ks_dht_s ks_dht_t; -typedef struct ks_dht_datagram_s ks_dht_datagram_t; -typedef struct ks_dht_job_s ks_dht_job_t; -typedef struct ks_dht_nodeid_s ks_dht_nodeid_t; -typedef struct ks_dht_token_s ks_dht_token_t; -typedef struct ks_dht_storageitem_pkey_s ks_dht_storageitem_pkey_t; -typedef struct ks_dht_storageitem_skey_s ks_dht_storageitem_skey_t; -typedef struct ks_dht_storageitem_signature_s ks_dht_storageitem_signature_t; -typedef struct ks_dht_message_s ks_dht_message_t; -typedef struct ks_dht_endpoint_s ks_dht_endpoint_t; -typedef struct ks_dht_transaction_s ks_dht_transaction_t; -typedef struct ks_dht_search_s ks_dht_search_t; -typedef struct ks_dht_publish_s ks_dht_publish_t; -typedef struct ks_dht_distribute_s ks_dht_distribute_t; -typedef struct ks_dht_node_s ks_dht_node_t; -typedef struct ks_dhtrt_routetable_s ks_dhtrt_routetable_t; -typedef struct ks_dhtrt_querynodes_s ks_dhtrt_querynodes_t; -typedef struct ks_dht_storageitem_s ks_dht_storageitem_t; - - -typedef ks_status_t (*ks_dht_job_callback_t)(ks_dht_t *dht, ks_dht_job_t *job); -typedef ks_status_t (*ks_dht_message_callback_t)(ks_dht_t *dht, ks_dht_message_t *message); -//typedef ks_status_t (*ks_dht_search_callback_t)(ks_dht_t *dht, ks_dht_search_t *search); -typedef ks_status_t (*ks_dht_storageitem_callback_t)(ks_dht_t *dht, ks_dht_storageitem_t *item); - - -struct ks_dht_datagram_s { - ks_pool_t *pool; - ks_dht_t *dht; - ks_dht_endpoint_t *endpoint; - ks_sockaddr_t raddr; - uint8_t buffer[KS_DHT_DATAGRAM_BUFFER_SIZE]; - ks_size_t buffer_length; -}; - -/** - * Note: This must remain a structure for casting from raw data - */ -struct ks_dht_nodeid_s { - uint8_t id[KS_DHT_NODEID_SIZE]; -}; - -enum ks_afflags_t { ifv4=AF_INET, ifv6=AF_INET6, ifboth=AF_INET+AF_INET6}; -enum ks_dht_nodetype_t { KS_DHT_REMOTE=0x01, - KS_DHT_LOCAL=0x02, - KS_DHT_BOTH=KS_DHT_REMOTE+KS_DHT_LOCAL }; - -enum ks_create_node_flags_t { - KS_DHTRT_CREATE_DEFAULT=0, - KS_DHTRT_CREATE_PING, - KS_DHTRT_CREATE_TOUCH -}; - -struct ks_dht_node_s { - ks_dht_nodeid_t nodeid; - ks_sockaddr_t addr; - enum ks_dht_nodetype_t type; /* local or remote */ - ks_dhtrt_routetable_t* table; - ks_rwl_t *reflock; -}; - -struct ks_dht_token_s { - uint8_t token[KS_DHT_TOKEN_SIZE]; -}; - -enum ks_dht_job_state_t { - KS_DHT_JOB_STATE_QUERYING, - KS_DHT_JOB_STATE_RESPONDING, - KS_DHT_JOB_STATE_EXPIRING, - KS_DHT_JOB_STATE_COMPLETING, -}; - -enum ks_dht_job_result_t { - KS_DHT_JOB_RESULT_SUCCESS = 0, - KS_DHT_JOB_RESULT_EXPIRED, - KS_DHT_JOB_RESULT_ERROR, - KS_DHT_JOB_RESULT_FAILURE, -}; - -struct ks_dht_job_s { - ks_pool_t *pool; - ks_dht_t *dht; - ks_dht_job_t *next; - - enum ks_dht_job_state_t state; - enum ks_dht_job_result_t result; - - ks_sockaddr_t raddr; // will obtain local endpoint node id when creating message using raddr - int32_t attempts; - - //enum ks_dht_job_type_t type; - ks_dht_job_callback_t query_callback; - ks_dht_job_callback_t finish_callback; - - void *data; - ks_dht_message_t *response; - - // job specific query parameters - ks_dht_nodeid_t query_target; - struct bencode *query_salt; - int64_t query_cas; - ks_dht_token_t query_token; - ks_dht_storageitem_t *query_storageitem; - - // error response parameters - int64_t error_code; - struct bencode *error_description; - - // job specific response parameters - ks_dht_node_t *response_id; - ks_dht_node_t *response_nodes[KS_DHT_RESPONSE_NODES_MAX_SIZE]; - ks_size_t response_nodes_count; - ks_dht_node_t *response_nodes6[KS_DHT_RESPONSE_NODES_MAX_SIZE]; - ks_size_t response_nodes6_count; - - ks_dht_token_t response_token; - int64_t response_seq; - ks_bool_t response_hasitem; - ks_dht_storageitem_t *response_storageitem; -}; - -struct ks_dhtrt_routetable_s { - void* internal; - ks_pool_t* pool; - ks_logger_t logger; -}; - -struct ks_dhtrt_querynodes_s { - ks_dht_nodeid_t nodeid; /* in: id to query */ - enum ks_afflags_t family; /* in: AF_INET or AF_INET6 or both */ - enum ks_dht_nodetype_t type; /* remote, local, or both */ - uint8_t max; /* in: maximum to return */ - uint8_t count; /* out: number returned */ - ks_dht_node_t* nodes[ KS_DHTRT_MAXQUERYSIZE ]; /* out: array of peers (ks_dht_node_t* nodes[incount]) */ -}; - -struct ks_dht_storageitem_pkey_s { - uint8_t key[KS_DHT_STORAGEITEM_PKEY_SIZE]; -}; - -struct ks_dht_storageitem_skey_s { - uint8_t key[KS_DHT_STORAGEITEM_SKEY_SIZE]; -}; - -struct ks_dht_storageitem_signature_s { - uint8_t sig[KS_DHT_STORAGEITEM_SIGNATURE_SIZE]; -}; - -struct ks_dht_message_s { - ks_pool_t *pool; - ks_dht_endpoint_t *endpoint; - ks_sockaddr_t raddr; - struct bencode *data; - uint8_t transactionid[KS_DHT_MESSAGE_TRANSACTIONID_MAX_SIZE]; - ks_size_t transactionid_length; - ks_dht_transaction_t *transaction; - char type[KS_DHT_MESSAGE_TYPE_MAX_SIZE]; - struct bencode *args; - ks_dht_nodeid_t args_id; -}; - -struct ks_dht_endpoint_s { - ks_pool_t *pool; - ks_sockaddr_t addr; - ks_socket_t sock; -}; - -struct ks_dht_transaction_s { - ks_pool_t *pool; - ks_dht_job_t *job; - uint32_t transactionid; - //ks_dht_nodeid_t target; // @todo look at moving this into job now - ks_dht_job_callback_t callback; - ks_time_t expiration; - ks_bool_t finished; -}; - -struct ks_dht_search_s { - ks_pool_t *pool; - ks_dhtrt_routetable_t *table; - ks_dht_nodeid_t target; - ks_dht_job_callback_t callback; - void *data; - ks_mutex_t *mutex; - ks_hash_t *searched; - int32_t searching; - ks_dht_node_t *results[KS_DHT_SEARCH_RESULTS_MAX_SIZE]; - ks_dht_nodeid_t distances[KS_DHT_SEARCH_RESULTS_MAX_SIZE]; - ks_size_t results_length; -}; - -struct ks_dht_publish_s { - ks_pool_t *pool; - ks_dht_job_callback_t callback; - void *data; - int64_t cas; - ks_dht_storageitem_t *item; -}; - -struct ks_dht_distribute_s { - ks_pool_t *pool; - ks_dht_storageitem_callback_t callback; - void *data; - ks_mutex_t *mutex; - int32_t publishing; - int64_t cas; - ks_dht_storageitem_t *item; -}; - -struct ks_dht_storageitem_s { - ks_pool_t *pool; - ks_dht_nodeid_t id; - ks_time_t expiration; - ks_time_t keepalive; - struct bencode *v; - - ks_mutex_t *mutex; - volatile int32_t refc; - ks_dht_storageitem_callback_t callback; - - ks_bool_t mutable; - ks_dht_storageitem_pkey_t pk; - ks_dht_storageitem_skey_t sk; - struct bencode *salt; - int64_t seq; - ks_dht_storageitem_signature_t sig; -}; - -struct ks_dht_s { - ks_pool_t *pool; - ks_bool_t pool_alloc; - - ks_thread_pool_t *tpool; - ks_bool_t tpool_alloc; - - ks_dht_nodeid_t nodeid; - // @todo make sure this node is unlocked, and never gets destroyed, should also never use local nodes in search results as they can be internal - // network addresses, not what others have contacted through - ks_dht_node_t *node; - - ks_bool_t autoroute; - ks_port_t autoroute_port; - - ks_hash_t *registry_type; - ks_hash_t *registry_query; - ks_hash_t *registry_error; - - ks_dht_endpoint_t **endpoints; - int32_t endpoints_length; - int32_t endpoints_size; - ks_hash_t *endpoints_hash; - struct pollfd *endpoints_poll; - - ks_q_t *send_q; - ks_dht_message_t *send_q_unsent; - uint8_t recv_buffer[KS_DHT_DATAGRAM_BUFFER_SIZE + 1]; // Add 1, if we receive it then overflow error - ks_size_t recv_buffer_length; - - ks_mutex_t *jobs_mutex; - ks_dht_job_t *jobs_first; - ks_dht_job_t *jobs_last; - - ks_time_t transactions_pulse; - ks_mutex_t *transactionid_mutex; - volatile uint32_t transactionid_next; - ks_hash_t *transactions_hash; - - ks_dhtrt_routetable_t *rt_ipv4; - ks_dhtrt_routetable_t *rt_ipv6; - - ks_time_t tokens_pulse; - volatile uint32_t token_secret_current; - volatile uint32_t token_secret_previous; - ks_time_t token_secret_expiration; - - ks_time_t storageitems_pulse; - ks_hash_t *storageitems_hash; -}; - -/** - * Constructor function for ks_dht_t. - * Will allocate and initialize internal state including registration of message handlers. - * @param dht dereferenced out pointer to the allocated dht instance - * @param pool pointer to the memory pool used by the dht instance, may be NULL to create a new memory pool internally - * @param tpool pointer to a thread pool used by the dht instance, may be NULL to create a new thread pool internally - * @param nodeid pointer to the nodeid for this dht instance - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_NO_MEM - */ -KS_DECLARE(ks_status_t) ks_dht_create(ks_dht_t **dht, ks_pool_t *pool, ks_thread_pool_t *tpool, ks_dht_nodeid_t *nodeid); - -/** - * Destructor function for ks_dht_t. - * Will deinitialize and deallocate internal state. - * @param dht dereferenced in/out pointer to the dht instance, NULL upon return - */ -KS_DECLARE(void) ks_dht_destroy(ks_dht_t **dht); - -/** - * Enable or disable (default) autorouting support. - * When enabled, autorouting will allow sending to remote addresses on interfaces which are not yet bound. - * The address will be bound with the provided autoroute port when this occurs. - * @param dht pointer to the dht instance - * @param autoroute enable or disable autorouting - * @param port when enabling autorouting this port will be used to bind new addresses, may be 0 to use the default DHT port - */ -KS_DECLARE(void) ks_dht_autoroute(ks_dht_t *dht, ks_bool_t autoroute, ks_port_t port); - -/** - * Register a callback for a specific message type. - * Will overwrite any duplicate handlers. - * @param dht pointer to the dht instance - * @param value string of the type text under the 'y' key of a message - * @param callback the callback to be called when a message matches - */ -KS_DECLARE(void) ks_dht_register_type(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback); - -/** - * Register a callback for a specific message query. - * Will overwrite any duplicate handlers. - * @param dht pointer to the dht instance - * @param value string of the type text under the 'q' key of a message - * @param callback the callback to be called when a message matches - */ -KS_DECLARE(void) ks_dht_register_query(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback); - -/** - * Register a callback for a specific message error. - * Will overwrite any duplicate handlers. - * @param dht pointer to the dht instance - * @param value string of the errorcode under the first item of the 'e' key of a message - * @param callback the callback to be called when a message matches - */ -KS_DECLARE(void) ks_dht_register_error(ks_dht_t *dht, const char *value, ks_dht_message_callback_t callback); - -/** - * Bind a local address and port for receiving UDP datagrams. - * @param dht pointer to the dht instance - * @param addr pointer to the local address information - * @param endpoint dereferenced out pointer to the allocated endpoint, may be NULL to ignore endpoint output - * @return The ks_status_t result: KS_STATUS_SUCCESS, KS_STATUS_FAIL, ... - * @see ks_socket_option - * @see ks_addr_bind - * @see ks_dht_endpoint_alloc - * @see ks_dht_endpoint_init - * @see ks_hash_insert - * @see ks_dhtrt_initroute - * @see ks_dhtrt_create_node - */ -KS_DECLARE(ks_status_t) ks_dht_bind(ks_dht_t *dht, const ks_sockaddr_t *addr, ks_dht_endpoint_t **endpoint); - -/** - * Pulse the internals of dht. - * Handles receiving UDP datagrams, dispatching processing, handles expirations, throttled message sending, route table pulsing, etc. - * @param dht pointer to the dht instance - * @param timeout timeout value used when polling sockets for new UDP datagrams - */ -KS_DECLARE(void) ks_dht_pulse(ks_dht_t *dht, int32_t timeout); - - -KS_DECLARE(char *) ks_dht_hex(const uint8_t *data, char *buffer, ks_size_t len); -KS_DECLARE(uint8_t *) ks_dht_dehex(uint8_t *data, const char *buffer, ks_size_t len); - - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_immutable(const uint8_t *value, ks_size_t value_length, ks_dht_nodeid_t *target); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_storageitem_target_mutable(ks_dht_storageitem_pkey_t *pk, const uint8_t *salt, ks_size_t salt_length, ks_dht_nodeid_t *target); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_storageitem_signature_generate(ks_dht_storageitem_signature_t *sig, - ks_dht_storageitem_skey_t *sk, - const uint8_t *salt, - ks_size_t salt_length, - int64_t sequence, - const uint8_t *value, - ks_size_t value_length); - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitem_reference(ks_dht_storageitem_t *item); - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitem_dereference(ks_dht_storageitem_t *item); - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitem_callback(ks_dht_storageitem_t *item, ks_dht_storageitem_callback_t callback); - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitems_read_lock(ks_dht_t *dht); - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitems_read_unlock(ks_dht_t *dht); - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitems_write_lock(ks_dht_t *dht); - -/** - * - */ -KS_DECLARE(void) ks_dht_storageitems_write_unlock(ks_dht_t *dht); - -/** - * - */ -KS_DECLARE(ks_dht_storageitem_t *) ks_dht_storageitems_find(ks_dht_t *dht, ks_dht_nodeid_t *target); - -/** - * - */ -KS_DECLARE(ks_status_t) ks_dht_storageitems_insert(ks_dht_t *dht, ks_dht_storageitem_t *item); - -/** - * - */ -KS_DECLARE(void) ks_dht_ping(ks_dht_t *dht, const ks_sockaddr_t *raddr, ks_dht_job_callback_t callback, void *data); - -/** - * - */ -KS_DECLARE(void) ks_dht_findnode(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - ks_dht_nodeid_t *target); - -/** - * - */ -KS_DECLARE(void) ks_dht_get(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - ks_dht_nodeid_t *target, - const uint8_t *salt, - ks_size_t salt_length); - -/** - * - */ -KS_DECLARE(void) ks_dht_put(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - ks_dht_token_t *token, - int64_t cas, - ks_dht_storageitem_t *item); - -/** - * Create a network search of the closest nodes to a target. - * @param dht pointer to the dht instance - * @param family either AF_INET or AF_INET6 for the appropriate network to search - * @param target pointer to the nodeid for the target to be searched - * @param callback an optional callback to add to the search when it is finished - * @param search dereferenced out pointer to the allocated search, may be NULL to ignore search output - * @see ks_dht_search_create - * @see ks_hash_insert - * @see ks_dht_findnode - */ -KS_DECLARE(void) ks_dht_search(ks_dht_t *dht, - ks_dht_job_callback_t callback, - void *data, - ks_dhtrt_routetable_t *table, - ks_dht_nodeid_t *target); - -KS_DECLARE(void) ks_dht_publish(ks_dht_t *dht, - const ks_sockaddr_t *raddr, - ks_dht_job_callback_t callback, - void *data, - int64_t cas, - ks_dht_storageitem_t *item); - -KS_DECLARE(void) ks_dht_distribute(ks_dht_t *dht, - ks_dht_storageitem_callback_t callback, - void *data, - ks_dhtrt_routetable_t *table, - int64_t cas, - ks_dht_storageitem_t *item); - -/** - * route table methods - * - */ -KS_DECLARE(ks_status_t) ks_dhtrt_initroute(ks_dhtrt_routetable_t **tableP, - ks_dht_t *dht, - ks_pool_t *pool); -KS_DECLARE(void) ks_dhtrt_deinitroute(ks_dhtrt_routetable_t **table); - -KS_DECLARE(ks_status_t) ks_dhtrt_create_node(ks_dhtrt_routetable_t* table, - ks_dht_nodeid_t nodeid, - enum ks_dht_nodetype_t type, - char* ip, unsigned short port, - enum ks_create_node_flags_t flags, - ks_dht_node_t** node); - -KS_DECLARE(ks_status_t) ks_dhtrt_delete_node(ks_dhtrt_routetable_t* table, ks_dht_node_t* node); - -KS_DECLARE(ks_status_t) ks_dhtrt_touch_node(ks_dhtrt_routetable_t* table, ks_dht_nodeid_t nodeid); -KS_DECLARE(ks_status_t) ks_dhtrt_expire_node(ks_dhtrt_routetable_t* table, ks_dht_nodeid_t nodeid); - -KS_DECLARE(uint8_t) ks_dhtrt_findclosest_nodes(ks_dhtrt_routetable_t* table, ks_dhtrt_querynodes_t* query); -KS_DECLARE(ks_dht_node_t*) ks_dhtrt_find_node(ks_dhtrt_routetable_t* table, ks_dht_nodeid_t id); - -KS_DECLARE(ks_status_t) ks_dhtrt_sharelock_node(ks_dht_node_t* node); -KS_DECLARE(ks_status_t) ks_dhtrt_release_node(ks_dht_node_t* node); -KS_DECLARE(ks_status_t) ks_dhtrt_release_querynodes(ks_dhtrt_querynodes_t* query); - -KS_DECLARE(void) ks_dhtrt_process_table(ks_dhtrt_routetable_t* table); - -KS_DECLARE(uint32_t) ks_dhtrt_serialize(ks_dhtrt_routetable_t* table, void** ptr); -KS_DECLARE(ks_status_t) ks_dhtrt_deserialize(ks_dhtrt_routetable_t* table, void* ptr); - -/* debugging aids */ -KS_DECLARE(void) ks_dhtrt_dump(ks_dhtrt_routetable_t* table, int level); - - -KS_END_EXTERN_C - -#endif /* KS_DHT_H */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libblade/src/include/unqlite.h b/libs/libblade/src/include/unqlite.h deleted file mode 100644 index dd7805ee10..0000000000 --- a/libs/libblade/src/include/unqlite.h +++ /dev/null @@ -1,950 +0,0 @@ -/* This file was automatically generated. Do not edit (Except for compile time directives)! */ -#ifndef _UNQLITE_H_ -#define _UNQLITE_H_ -/* - * Symisc UnQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2016, Symisc Systems http://unqlite.org/ - * Version 1.1.7 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ -/* - * Copyright (C) 2012, 2016 Symisc Systems, S.U.A.R.L [M.I.A.G Mrad Chems Eddine ]. - * 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 SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SYMISC SYSTEMS - * 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. - */ - /* $SymiscID: unqlite.h v1.2 Win10 2106-12-02 00:04:12 stable $ */ -#include /* needed for the definition of va_list */ -/* - * Compile time engine version, signature, identification in the symisc source tree - * and copyright notice. - * Each macro have an equivalent C interface associated with it that provide the same - * information but are associated with the library instead of the header file. - * Refer to [unqlite_lib_version()], [unqlite_lib_signature()], [unqlite_lib_ident()] and - * [unqlite_lib_copyright()] for more information. - */ -/* - * The UNQLITE_VERSION C preprocessor macroevaluates to a string literal - * that is the unqlite version in the format "X.Y.Z" where X is the major - * version number and Y is the minor version number and Z is the release - * number. - */ -#define UNQLITE_VERSION "1.1.7" -/* - * The UNQLITE_VERSION_NUMBER C preprocessor macro resolves to an integer - * with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same - * numbers used in [UNQLITE_VERSION]. - */ -#define UNQLITE_VERSION_NUMBER 1001007 -/* - * The UNQLITE_SIG C preprocessor macro evaluates to a string - * literal which is the public signature of the unqlite engine. - * This signature could be included for example in a host-application - * generated Server MIME header as follows: - * Server: YourWebServer/x.x unqlite/x.x.x \r\n - */ -#define UNQLITE_SIG "unqlite/1.1.7" -/* - * UnQLite identification in the Symisc source tree: - * Each particular check-in of a particular software released - * by symisc systems have an unique identifier associated with it. - * This macro hold the one associated with unqlite. - */ -#define UNQLITE_IDENT "unqlite:b172a1e2c3f62fb35c8e1fb2795121f82356cad6" -/* - * Copyright notice. - * If you have any questions about the licensing situation, please - * visit http://unqlite.org/licensing.html - * or contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - */ -#define UNQLITE_COPYRIGHT "Copyright (C) Symisc Systems, S.U.A.R.L [Mrad Chems Eddine ] 2012-2016, http://unqlite.org/" - -/* Forward declaration to public objects */ -typedef struct unqlite_io_methods unqlite_io_methods; -typedef struct unqlite_kv_methods unqlite_kv_methods; -typedef struct unqlite_kv_engine unqlite_kv_engine; -typedef struct jx9_io_stream unqlite_io_stream; -typedef struct jx9_context unqlite_context; -typedef struct jx9_value unqlite_value; -typedef struct unqlite_vfs unqlite_vfs; -typedef struct unqlite_vm unqlite_vm; -typedef struct unqlite unqlite; -/* - * ------------------------------ - * Compile time directives - * ------------------------------ - * For most purposes, UnQLite can be built just fine using the default compilation options. - * However, if required, the compile-time options documented below can be used to omit UnQLite - * features (resulting in a smaller compiled library size) or to change the default values - * of some parameters. - * Every effort has been made to ensure that the various combinations of compilation options - * work harmoniously and produce a working library. - * - * UNQLITE_ENABLE_THREADS - * This option controls whether or not code is included in UnQLite to enable it to operate - * safely in a multithreaded environment. The default is not. All mutexing code is omitted - * and it is unsafe to use UnQLite in a multithreaded program. When compiled with the - * UNQLITE_ENABLE_THREADS directive enabled, UnQLite can be used in a multithreaded program - * and it is safe to share the same virtual machine and engine handle between two or more threads. - * The value of UNQLITE_ENABLE_THREADS can be determined at run-time using the unqlite_lib_is_threadsafe() - * interface. - * When UnQLite has been compiled with threading support then the threading mode can be altered - * at run-time using the unqlite_lib_config() interface together with one of these verbs: - * UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE - * UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI - * Platforms others than Windows and UNIX systems must install their own mutex subsystem via - * unqlite_lib_config() with a configuration verb set to UNQLITE_LIB_CONFIG_USER_MUTEX. - * Otherwise the library is not threadsafe. - * Note that you must link UnQLite with the POSIX threads library under UNIX systems (i.e: -lpthread). - * - * Options To Omit/Enable Features - * - * The following options can be used to reduce the size of the compiled library by omitting optional - * features. This is probably only useful in embedded systems where space is especially tight, as even - * with all features included the UnQLite library is relatively small. Don't forget to tell your - * compiler to optimize for binary size! (the -Os option if using GCC). Telling your compiler - * to optimize for size usually has a much larger impact on library footprint than employing - * any of these compile-time options. - * - * JX9_DISABLE_BUILTIN_FUNC - * Jx9 is shipped with more than 312 built-in functions suitable for most purposes like - * string and INI processing, ZIP extracting, Base64 encoding/decoding, JSON encoding/decoding - * and so forth. - * If this directive is enabled, then all built-in Jx9 functions are omitted from the build. - * Note that special functions such as db_create(), db_store(), db_fetch(), etc. are not omitted - * from the build and are not affected by this directive. - * - * JX9_ENABLE_MATH_FUNC - * If this directive is enabled, built-in math functions such as sqrt(), abs(), log(), ceil(), etc. - * are included in the build. Note that you may need to link UnQLite with the math library in same - * Linux/BSD flavor (i.e: -lm). - * - * JX9_DISABLE_DISK_IO - * If this directive is enabled, built-in VFS functions such as chdir(), mkdir(), chroot(), unlink(), - * sleep(), etc. are omitted from the build. - * - * UNQLITE_ENABLE_JX9_HASH_IO - * If this directive is enabled, built-in hash functions such as md5(), sha1(), md5_file(), crc32(), etc. - * are included in the build. - */ -/* Symisc public definitions */ -#if !defined(SYMISC_STANDARD_DEFS) -#define SYMISC_STANDARD_DEFS -#if defined (_WIN32) || defined (WIN32) || defined(__MINGW32__) || defined (_MSC_VER) || defined (_WIN32_WCE) -/* Windows Systems */ -#if !defined(__WINNT__) -#define __WINNT__ -#endif -/* - * Determine if we are dealing with WindowsCE - which has a much - * reduced API. - */ -#if defined(_WIN32_WCE) -#ifndef __WIN_CE__ -#define __WIN_CE__ -#endif /* __WIN_CE__ */ -#endif /* _WIN32_WCE */ -#else -/* - * By default we will assume that we are compiling on a UNIX systems. - * Otherwise the OS_OTHER directive must be defined. - */ -#if !defined(OS_OTHER) -#if !defined(__UNIXES__) -#define __UNIXES__ -#endif /* __UNIXES__ */ -#else -#endif /* OS_OTHER */ -#endif /* __WINNT__/__UNIXES__ */ -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef signed __int64 sxi64; /* 64 bits(8 bytes) signed int64 */ -typedef unsigned __int64 sxu64; /* 64 bits(8 bytes) unsigned int64 */ -#else -typedef signed long long int sxi64; /* 64 bits(8 bytes) signed int64 */ -typedef unsigned long long int sxu64; /* 64 bits(8 bytes) unsigned int64 */ -#endif /* _MSC_VER */ -/* Signature of the consumer routine */ -typedef int (*ProcConsumer)(const void *, unsigned int, void *); -/* Forward reference */ -typedef struct SyMutexMethods SyMutexMethods; -typedef struct SyMemMethods SyMemMethods; -typedef struct SyString SyString; -typedef struct syiovec syiovec; -typedef struct SyMutex SyMutex; -typedef struct Sytm Sytm; -/* Scatter and gather array. */ -struct syiovec -{ -#if defined (__WINNT__) - /* Same fields type and offset as WSABUF structure defined one winsock2 header */ - unsigned long nLen; - char *pBase; -#else - void *pBase; - unsigned long nLen; -#endif -}; -struct SyString -{ - const char *zString; /* Raw string (may not be null terminated) */ - unsigned int nByte; /* Raw string length */ -}; -/* Time structure. */ -struct Sytm -{ - int tm_sec; /* seconds (0 - 60) */ - int tm_min; /* minutes (0 - 59) */ - int tm_hour; /* hours (0 - 23) */ - int tm_mday; /* day of month (1 - 31) */ - int tm_mon; /* month of year (0 - 11) */ - int tm_year; /* year + 1900 */ - int tm_wday; /* day of week (Sunday = 0) */ - int tm_yday; /* day of year (0 - 365) */ - int tm_isdst; /* is summer time in effect? */ - char *tm_zone; /* abbreviation of timezone name */ - long tm_gmtoff; /* offset from UTC in seconds */ -}; -/* Convert a tm structure (struct tm *) found in to a Sytm structure */ -#define STRUCT_TM_TO_SYTM(pTM, pSYTM) \ - (pSYTM)->tm_hour = (pTM)->tm_hour;\ - (pSYTM)->tm_min = (pTM)->tm_min;\ - (pSYTM)->tm_sec = (pTM)->tm_sec;\ - (pSYTM)->tm_mon = (pTM)->tm_mon;\ - (pSYTM)->tm_mday = (pTM)->tm_mday;\ - (pSYTM)->tm_year = (pTM)->tm_year + 1900;\ - (pSYTM)->tm_yday = (pTM)->tm_yday;\ - (pSYTM)->tm_wday = (pTM)->tm_wday;\ - (pSYTM)->tm_isdst = (pTM)->tm_isdst;\ - (pSYTM)->tm_gmtoff = 0;\ - (pSYTM)->tm_zone = 0; - -/* Convert a SYSTEMTIME structure (LPSYSTEMTIME: Windows Systems only ) to a Sytm structure */ -#define SYSTEMTIME_TO_SYTM(pSYSTIME, pSYTM) \ - (pSYTM)->tm_hour = (pSYSTIME)->wHour;\ - (pSYTM)->tm_min = (pSYSTIME)->wMinute;\ - (pSYTM)->tm_sec = (pSYSTIME)->wSecond;\ - (pSYTM)->tm_mon = (pSYSTIME)->wMonth - 1;\ - (pSYTM)->tm_mday = (pSYSTIME)->wDay;\ - (pSYTM)->tm_year = (pSYSTIME)->wYear;\ - (pSYTM)->tm_yday = 0;\ - (pSYTM)->tm_wday = (pSYSTIME)->wDayOfWeek;\ - (pSYTM)->tm_gmtoff = 0;\ - (pSYTM)->tm_isdst = -1;\ - (pSYTM)->tm_zone = 0; - -/* Dynamic memory allocation methods. */ -struct SyMemMethods -{ - void * (*xAlloc)(unsigned int); /* [Required:] Allocate a memory chunk */ - void * (*xRealloc)(void *, unsigned int); /* [Required:] Re-allocate a memory chunk */ - void (*xFree)(void *); /* [Required:] Release a memory chunk */ - unsigned int (*xChunkSize)(void *); /* [Optional:] Return chunk size */ - int (*xInit)(void *); /* [Optional:] Initialization callback */ - void (*xRelease)(void *); /* [Optional:] Release callback */ - void *pUserData; /* [Optional:] First argument to xInit() and xRelease() */ -}; -/* Out of memory callback signature. */ -typedef int (*ProcMemError)(void *); -/* Mutex methods. */ -struct SyMutexMethods -{ - int (*xGlobalInit)(void); /* [Optional:] Global mutex initialization */ - void (*xGlobalRelease)(void); /* [Optional:] Global Release callback () */ - SyMutex * (*xNew)(int); /* [Required:] Request a new mutex */ - void (*xRelease)(SyMutex *); /* [Optional:] Release a mutex */ - void (*xEnter)(SyMutex *); /* [Required:] Enter mutex */ - int (*xTryEnter)(SyMutex *); /* [Optional:] Try to enter a mutex */ - void (*xLeave)(SyMutex *); /* [Required:] Leave a locked mutex */ -}; -#if defined (_MSC_VER) || defined (__MINGW32__) || defined (__GNUC__) && defined (__declspec) -#define SX_APIIMPORT __declspec(dllimport) -#define SX_APIEXPORT __declspec(dllexport) -#else -#define SX_APIIMPORT -#define SX_APIEXPORT -#endif -/* Standard return values from Symisc public interfaces */ -#define SXRET_OK 0 /* Not an error */ -#define SXERR_MEM (-1) /* Out of memory */ -#define SXERR_IO (-2) /* IO error */ -#define SXERR_EMPTY (-3) /* Empty field */ -#define SXERR_LOCKED (-4) /* Locked operation */ -#define SXERR_ORANGE (-5) /* Out of range value */ -#define SXERR_NOTFOUND (-6) /* Item not found */ -#define SXERR_LIMIT (-7) /* Limit reached */ -#define SXERR_MORE (-8) /* Need more input */ -#define SXERR_INVALID (-9) /* Invalid parameter */ -#define SXERR_ABORT (-10) /* User callback request an operation abort */ -#define SXERR_EXISTS (-11) /* Item exists */ -#define SXERR_SYNTAX (-12) /* Syntax error */ -#define SXERR_UNKNOWN (-13) /* Unknown error */ -#define SXERR_BUSY (-14) /* Busy operation */ -#define SXERR_OVERFLOW (-15) /* Stack or buffer overflow */ -#define SXERR_WILLBLOCK (-16) /* Operation will block */ -#define SXERR_NOTIMPLEMENTED (-17) /* Operation not implemented */ -#define SXERR_EOF (-18) /* End of input */ -#define SXERR_PERM (-19) /* Permission error */ -#define SXERR_NOOP (-20) /* No-op */ -#define SXERR_FORMAT (-21) /* Invalid format */ -#define SXERR_NEXT (-22) /* Not an error */ -#define SXERR_OS (-23) /* System call return an error */ -#define SXERR_CORRUPT (-24) /* Corrupted pointer */ -#define SXERR_CONTINUE (-25) /* Not an error: Operation in progress */ -#define SXERR_NOMATCH (-26) /* No match */ -#define SXERR_RESET (-27) /* Operation reset */ -#define SXERR_DONE (-28) /* Not an error */ -#define SXERR_SHORT (-29) /* Buffer too short */ -#define SXERR_PATH (-30) /* Path error */ -#define SXERR_TIMEOUT (-31) /* Timeout */ -#define SXERR_BIG (-32) /* Too big for processing */ -#define SXERR_RETRY (-33) /* Retry your call */ -#define SXERR_IGNORE (-63) /* Ignore */ -#endif /* SYMISC_PUBLIC_DEFS */ -/* - * Marker for exported interfaces. - */ -#define UNQLITE_APIEXPORT SX_APIEXPORT -/* - * If compiling for a processor that lacks floating point - * support, substitute integer for floating-point. - */ -#ifdef UNQLITE_OMIT_FLOATING_POINT -typedef sxi64 uqlite_real; -#else -typedef double unqlite_real; -#endif -typedef sxi64 unqlite_int64; -/* Standard UnQLite return values */ -#define UNQLITE_OK SXRET_OK /* Successful result */ -/* Beginning of error codes */ -#define UNQLITE_NOMEM SXERR_MEM /* Out of memory */ -#define UNQLITE_ABORT SXERR_ABORT /* Another thread have released this instance */ -#define UNQLITE_IOERR SXERR_IO /* IO error */ -#define UNQLITE_CORRUPT SXERR_CORRUPT /* Corrupt pointer */ -#define UNQLITE_LOCKED SXERR_LOCKED /* Forbidden Operation */ -#define UNQLITE_BUSY SXERR_BUSY /* The database file is locked */ -#define UNQLITE_DONE SXERR_DONE /* Operation done */ -#define UNQLITE_PERM SXERR_PERM /* Permission error */ -#define UNQLITE_NOTIMPLEMENTED SXERR_NOTIMPLEMENTED /* Method not implemented by the underlying Key/Value storage engine */ -#define UNQLITE_NOTFOUND SXERR_NOTFOUND /* No such record */ -#define UNQLITE_NOOP SXERR_NOOP /* No such method */ -#define UNQLITE_INVALID SXERR_INVALID /* Invalid parameter */ -#define UNQLITE_EOF SXERR_EOF /* End Of Input */ -#define UNQLITE_UNKNOWN SXERR_UNKNOWN /* Unknown configuration option */ -#define UNQLITE_LIMIT SXERR_LIMIT /* Database limit reached */ -#define UNQLITE_EXISTS SXERR_EXISTS /* Record exists */ -#define UNQLITE_EMPTY SXERR_EMPTY /* Empty record */ -#define UNQLITE_COMPILE_ERR (-70) /* Compilation error */ -#define UNQLITE_VM_ERR (-71) /* Virtual machine error */ -#define UNQLITE_FULL (-73) /* Full database (unlikely) */ -#define UNQLITE_CANTOPEN (-74) /* Unable to open the database file */ -#define UNQLITE_READ_ONLY (-75) /* Read only Key/Value storage engine */ -#define UNQLITE_LOCKERR (-76) /* Locking protocol error */ -/* end-of-error-codes */ -/* - * Database Handle Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure an UnQLite database handle. - * These constants must be passed as the second argument to [unqlite_config()]. - * - * Each options require a variable number of arguments. - * The [unqlite_config()] interface will return UNQLITE_OK on success, any other - * return value indicates failure. - * For a full discussion on the configuration verbs and their expected - * parameters, please refer to this page: - * http://unqlite.org/c_api/unqlite_config.html - */ -#define UNQLITE_CONFIG_JX9_ERR_LOG 1 /* TWO ARGUMENTS: const char **pzBuf, int *pLen */ -#define UNQLITE_CONFIG_MAX_PAGE_CACHE 2 /* ONE ARGUMENT: int nMaxPage */ -#define UNQLITE_CONFIG_ERR_LOG 3 /* TWO ARGUMENTS: const char **pzBuf, int *pLen */ -#define UNQLITE_CONFIG_KV_ENGINE 4 /* ONE ARGUMENT: const char *zKvName */ -#define UNQLITE_CONFIG_DISABLE_AUTO_COMMIT 5 /* NO ARGUMENTS */ -#define UNQLITE_CONFIG_GET_KV_NAME 6 /* ONE ARGUMENT: const char **pzPtr */ -/* - * UnQLite/Jx9 Virtual Machine Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the Jx9 (Via UnQLite) Virtual machine. - * These constants must be passed as the second argument to the [unqlite_vm_config()] - * interface. - * Each options require a variable number of arguments. - * The [unqlite_vm_config()] interface will return UNQLITE_OK on success, any other return - * value indicates failure. - * There are many options but the most importants are: UNQLITE_VM_CONFIG_OUTPUT which install - * a VM output consumer callback, UNQLITE_VM_CONFIG_HTTP_REQUEST which parse and register - * a HTTP request and UNQLITE_VM_CONFIG_ARGV_ENTRY which populate the $argv array. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://unqlite.org/c_api/unqlite_vm_config.html - */ -#define UNQLITE_VM_CONFIG_OUTPUT 1 /* TWO ARGUMENTS: int (*xConsumer)(const void *pOut, unsigned int nLen, void *pUserData), void *pUserData */ -#define UNQLITE_VM_CONFIG_IMPORT_PATH 2 /* ONE ARGUMENT: const char *zIncludePath */ -#define UNQLITE_VM_CONFIG_ERR_REPORT 3 /* NO ARGUMENTS: Report all run-time errors in the VM output */ -#define UNQLITE_VM_CONFIG_RECURSION_DEPTH 4 /* ONE ARGUMENT: int nMaxDepth */ -#define UNQLITE_VM_OUTPUT_LENGTH 5 /* ONE ARGUMENT: unsigned int *pLength */ -#define UNQLITE_VM_CONFIG_CREATE_VAR 6 /* TWO ARGUMENTS: const char *zName, unqlite_value *pValue */ -#define UNQLITE_VM_CONFIG_HTTP_REQUEST 7 /* TWO ARGUMENTS: const char *zRawRequest, int nRequestLength */ -#define UNQLITE_VM_CONFIG_SERVER_ATTR 8 /* THREE ARGUMENTS: const char *zKey, const char *zValue, int nLen */ -#define UNQLITE_VM_CONFIG_ENV_ATTR 9 /* THREE ARGUMENTS: const char *zKey, const char *zValue, int nLen */ -#define UNQLITE_VM_CONFIG_EXEC_VALUE 10 /* ONE ARGUMENT: unqlite_value **ppValue */ -#define UNQLITE_VM_CONFIG_IO_STREAM 11 /* ONE ARGUMENT: const unqlite_io_stream *pStream */ -#define UNQLITE_VM_CONFIG_ARGV_ENTRY 12 /* ONE ARGUMENT: const char *zValue */ -#define UNQLITE_VM_CONFIG_EXTRACT_OUTPUT 13 /* TWO ARGUMENTS: const void **ppOut, unsigned int *pOutputLen */ -/* - * Storage engine configuration commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the underlying storage engine (i.e Hash, B+tree, R+tree). - * These constants must be passed as the first argument to [unqlite_kv_config()]. - * Each options require a variable number of arguments. - * The [unqlite_kv_config()] interface will return UNQLITE_OK on success, any other return - * value indicates failure. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://unqlite.org/c_api/unqlite_kv_config.html - */ -#define UNQLITE_KV_CONFIG_HASH_FUNC 1 /* ONE ARGUMENT: unsigned int (*xHash)(const void *,unsigned int) */ -#define UNQLITE_KV_CONFIG_CMP_FUNC 2 /* ONE ARGUMENT: int (*xCmp)(const void *,const void *,unsigned int) */ -/* - * Global Library Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the whole library. - * These constants must be passed as the first argument to [unqlite_lib_config()]. - * - * Each options require a variable number of arguments. - * The [unqlite_lib_config()] interface will return UNQLITE_OK on success, any other return - * value indicates failure. - * Notes: - * The default configuration is recommended for most applications and so the call to - * [unqlite_lib_config()] is usually not necessary. It is provided to support rare - * applications with unusual needs. - * The [unqlite_lib_config()] interface is not threadsafe. The application must insure that - * no other [unqlite_*()] interfaces are invoked by other threads while [unqlite_lib_config()] - * is running. Furthermore, [unqlite_lib_config()] may only be invoked prior to library - * initialization using [unqlite_lib_init()] or [unqlite_init()] or after shutdown - * by [unqlite_lib_shutdown()]. If [unqlite_lib_config()] is called after [unqlite_lib_init()] - * or [unqlite_init()] and before [unqlite_lib_shutdown()] then it will return UNQLITE_LOCKED. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://unqlite.org/c_api/unqlite_lib.html - */ -#define UNQLITE_LIB_CONFIG_USER_MALLOC 1 /* ONE ARGUMENT: const SyMemMethods *pMemMethods */ -#define UNQLITE_LIB_CONFIG_MEM_ERR_CALLBACK 2 /* TWO ARGUMENTS: int (*xMemError)(void *), void *pUserData */ -#define UNQLITE_LIB_CONFIG_USER_MUTEX 3 /* ONE ARGUMENT: const SyMutexMethods *pMutexMethods */ -#define UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE 4 /* NO ARGUMENTS */ -#define UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI 5 /* NO ARGUMENTS */ -#define UNQLITE_LIB_CONFIG_VFS 6 /* ONE ARGUMENT: const unqlite_vfs *pVfs */ -#define UNQLITE_LIB_CONFIG_STORAGE_ENGINE 7 /* ONE ARGUMENT: unqlite_kv_methods *pStorage */ -#define UNQLITE_LIB_CONFIG_PAGE_SIZE 8 /* ONE ARGUMENT: int iPageSize */ -/* - * These bit values are intended for use in the 3rd parameter to the [unqlite_open()] interface - * and in the 4th parameter to the xOpen method of the [unqlite_vfs] object. - */ -#define UNQLITE_OPEN_READONLY 0x00000001 /* Read only mode. Ok for [unqlite_open] */ -#define UNQLITE_OPEN_READWRITE 0x00000002 /* Ok for [unqlite_open] */ -#define UNQLITE_OPEN_CREATE 0x00000004 /* Ok for [unqlite_open] */ -#define UNQLITE_OPEN_EXCLUSIVE 0x00000008 /* VFS only */ -#define UNQLITE_OPEN_TEMP_DB 0x00000010 /* VFS only */ -#define UNQLITE_OPEN_NOMUTEX 0x00000020 /* Ok for [unqlite_open] */ -#define UNQLITE_OPEN_OMIT_JOURNALING 0x00000040 /* Omit journaling for this database. Ok for [unqlite_open] */ -#define UNQLITE_OPEN_IN_MEMORY 0x00000080 /* An in memory database. Ok for [unqlite_open]*/ -#define UNQLITE_OPEN_MMAP 0x00000100 /* Obtain a memory view of the whole file. Ok for [unqlite_open] */ -/* - * Synchronization Type Flags - * - * When UnQLite invokes the xSync() method of an [unqlite_io_methods] object it uses - * a combination of these integer values as the second argument. - * - * When the UNQLITE_SYNC_DATAONLY flag is used, it means that the sync operation only - * needs to flush data to mass storage. Inode information need not be flushed. - * If the lower four bits of the flag equal UNQLITE_SYNC_NORMAL, that means to use normal - * fsync() semantics. If the lower four bits equal UNQLITE_SYNC_FULL, that means to use - * Mac OS X style fullsync instead of fsync(). - */ -#define UNQLITE_SYNC_NORMAL 0x00002 -#define UNQLITE_SYNC_FULL 0x00003 -#define UNQLITE_SYNC_DATAONLY 0x00010 -/* - * File Locking Levels - * - * UnQLite uses one of these integer values as the second - * argument to calls it makes to the xLock() and xUnlock() methods - * of an [unqlite_io_methods] object. - */ -#define UNQLITE_LOCK_NONE 0 -#define UNQLITE_LOCK_SHARED 1 -#define UNQLITE_LOCK_RESERVED 2 -#define UNQLITE_LOCK_PENDING 3 -#define UNQLITE_LOCK_EXCLUSIVE 4 -/* - * CAPIREF: OS Interface: Open File Handle - * - * An [unqlite_file] object represents an open file in the [unqlite_vfs] OS interface - * layer. - * Individual OS interface implementations will want to subclass this object by appending - * additional fields for their own use. The pMethods entry is a pointer to an - * [unqlite_io_methods] object that defines methods for performing - * I/O operations on the open file. -*/ -typedef struct unqlite_file unqlite_file; -struct unqlite_file { - const unqlite_io_methods *pMethods; /* Methods for an open file. MUST BE FIRST */ -}; -/* - * CAPIREF: OS Interface: File Methods Object - * - * Every file opened by the [unqlite_vfs] xOpen method populates an - * [unqlite_file] object (or, more commonly, a subclass of the - * [unqlite_file] object) with a pointer to an instance of this object. - * This object defines the methods used to perform various operations - * against the open file represented by the [unqlite_file] object. - * - * If the xOpen method sets the unqlite_file.pMethods element - * to a non-NULL pointer, then the unqlite_io_methods.xClose method - * may be invoked even if the xOpen reported that it failed. The - * only way to prevent a call to xClose following a failed xOpen - * is for the xOpen to set the unqlite_file.pMethods element to NULL. - * - * The flags argument to xSync may be one of [UNQLITE_SYNC_NORMAL] or - * [UNQLITE_SYNC_FULL]. The first choice is the normal fsync(). - * The second choice is a Mac OS X style fullsync. The [UNQLITE_SYNC_DATAONLY] - * flag may be ORed in to indicate that only the data of the file - * and not its inode needs to be synced. - * - * The integer values to xLock() and xUnlock() are one of - * - * UNQLITE_LOCK_NONE - * UNQLITE_LOCK_SHARED - * UNQLITE_LOCK_RESERVED - * UNQLITE_LOCK_PENDING - * UNQLITE_LOCK_EXCLUSIVE - * - * xLock() increases the lock. xUnlock() decreases the lock. - * 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. - * - * The xSectorSize() method returns the sector size of the device that underlies - * the file. The sector size is the minimum write that can be performed without - * disturbing other bytes in the file. - * - */ -struct unqlite_io_methods { - int iVersion; /* Structure version number (currently 1) */ - int (*xClose)(unqlite_file*); - int (*xRead)(unqlite_file*, void*, unqlite_int64 iAmt, unqlite_int64 iOfst); - int (*xWrite)(unqlite_file*, const void*, unqlite_int64 iAmt, unqlite_int64 iOfst); - int (*xTruncate)(unqlite_file*, unqlite_int64 size); - int (*xSync)(unqlite_file*, int flags); - int (*xFileSize)(unqlite_file*, unqlite_int64 *pSize); - int (*xLock)(unqlite_file*, int); - int (*xUnlock)(unqlite_file*, int); - int (*xCheckReservedLock)(unqlite_file*, int *pResOut); - int (*xSectorSize)(unqlite_file*); -}; -/* - * CAPIREF: OS Interface Object - * - * An instance of the unqlite_vfs object defines the interface between - * the UnQLite core and the underlying operating system. The "vfs" - * in the name of the object stands for "Virtual File System". - * - * Only a single vfs can be registered within the UnQLite core. - * Vfs registration is done using the [unqlite_lib_config()] interface - * with a configuration verb set to UNQLITE_LIB_CONFIG_VFS. - * Note that Windows and UNIX (Linux, FreeBSD, Solaris, Mac OS X, etc.) users - * does not have to worry about registering and installing a vfs since UnQLite - * come with a built-in vfs for these platforms that implements most the methods - * defined below. - * - * Clients running on exotic systems (ie: Other than Windows and UNIX systems) - * must register their own vfs in order to be able to use the UnQLite library. - * - * The value of the iVersion field is initially 1 but may be larger in - * future versions of UnQLite. - * - * The szOsFile field is the size of the subclassed [unqlite_file] structure - * used by this VFS. mxPathname is the maximum length of a pathname in this VFS. - * - * At least szOsFile bytes of memory are allocated by UnQLite to hold the [unqlite_file] - * structure passed as the third argument to xOpen. The xOpen method does not have to - * allocate the structure; it should just fill it in. Note that the xOpen method must - * set the unqlite_file.pMethods to either a valid [unqlite_io_methods] object or to NULL. - * xOpen must do this even if the open fails. UnQLite expects that the unqlite_file.pMethods - * element will be valid after xOpen returns regardless of the success or failure of the - * xOpen call. - * - */ -struct unqlite_vfs { - const char *zName; /* Name of this virtual file system [i.e: Windows, UNIX, etc.] */ - int iVersion; /* Structure version number (currently 1) */ - int szOsFile; /* Size of subclassed unqlite_file */ - int mxPathname; /* Maximum file pathname length */ - int (*xOpen)(unqlite_vfs*, const char *zName, unqlite_file*,unsigned int flags); - int (*xDelete)(unqlite_vfs*, const char *zName, int syncDir); - int (*xAccess)(unqlite_vfs*, const char *zName, int flags, int *pResOut); - int (*xFullPathname)(unqlite_vfs*, const char *zName,int buf_len,char *zBuf); - int (*xTmpDir)(unqlite_vfs*,char *zBuf,int buf_len); - int (*xSleep)(unqlite_vfs*, int microseconds); - int (*xCurrentTime)(unqlite_vfs*,Sytm *pOut); - int (*xGetLastError)(unqlite_vfs*, int, char *); -}; -/* - * Flags for the xAccess VFS method - * - * These integer constants can be used as the third parameter to - * the xAccess method of an [unqlite_vfs] object. They determine - * what kind of permissions the xAccess method is looking for. - * With UNQLITE_ACCESS_EXISTS, the xAccess method - * simply checks whether the file exists. - * With UNQLITE_ACCESS_READWRITE, the xAccess method - * checks whether the named directory is both readable and writable - * (in other words, if files can be added, removed, and renamed within - * the directory). - * The UNQLITE_ACCESS_READWRITE constant is currently used only by the - * [temp_store_directory pragma], though this could change in a future - * release of UnQLite. - * With UNQLITE_ACCESS_READ, the xAccess method - * checks whether the file is readable. The UNQLITE_ACCESS_READ constant is - * currently unused, though it might be used in a future release of - * UnQLite. - */ -#define UNQLITE_ACCESS_EXISTS 0 -#define UNQLITE_ACCESS_READWRITE 1 -#define UNQLITE_ACCESS_READ 2 -/* - * The type used to represent a page number. The first page in a file - * is called page 1. 0 is used to represent "not a page". - * A page number is an unsigned 64-bit integer. - */ -typedef sxu64 pgno; -/* - * A database disk page is represented by an instance - * of the follwoing structure. - */ -typedef struct unqlite_page unqlite_page; -struct unqlite_page -{ - unsigned char *zData; /* Content of this page */ - void *pUserData; /* Extra content */ - pgno pgno; /* Page number for this page */ -}; -/* - * UnQLite handle to the underlying Key/Value Storage Engine (See below). - */ -typedef void * unqlite_kv_handle; -/* - * UnQLite pager IO methods. - * - * An instance of the following structure define the exported methods of the UnQLite pager - * to the underlying Key/Value storage engine. - */ -typedef struct unqlite_kv_io unqlite_kv_io; -struct unqlite_kv_io -{ - unqlite_kv_handle pHandle; /* UnQLite handle passed as the first parameter to the - * method defined below. - */ - unqlite_kv_methods *pMethods; /* Underlying storage engine */ - /* Pager methods */ - int (*xGet)(unqlite_kv_handle,pgno,unqlite_page **); - int (*xLookup)(unqlite_kv_handle,pgno,unqlite_page **); - int (*xNew)(unqlite_kv_handle,unqlite_page **); - int (*xWrite)(unqlite_page *); - int (*xDontWrite)(unqlite_page *); - int (*xDontJournal)(unqlite_page *); - int (*xDontMkHot)(unqlite_page *); - int (*xPageRef)(unqlite_page *); - int (*xPageUnref)(unqlite_page *); - int (*xPageSize)(unqlite_kv_handle); - int (*xReadOnly)(unqlite_kv_handle); - unsigned char * (*xTmpPage)(unqlite_kv_handle); - void (*xSetUnpin)(unqlite_kv_handle,void (*xPageUnpin)(void *)); - void (*xSetReload)(unqlite_kv_handle,void (*xPageReload)(void *)); - void (*xErr)(unqlite_kv_handle,const char *); -}; -/* - * Key/Value Storage Engine Cursor Object - * - * An instance of a subclass of the following object defines a cursor - * used to scan through a key-value storage engine. - */ -typedef struct unqlite_kv_cursor unqlite_kv_cursor; -struct unqlite_kv_cursor -{ - unqlite_kv_engine *pStore; /* Must be first */ - /* Subclasses will typically add additional fields */ -}; -/* - * Possible seek positions. - */ -#define UNQLITE_CURSOR_MATCH_EXACT 1 -#define UNQLITE_CURSOR_MATCH_LE 2 -#define UNQLITE_CURSOR_MATCH_GE 3 -/* - * Key/Value Storage Engine. - * - * A Key-Value storage engine is defined by an instance of the following - * object. - * UnQLite works with run-time interchangeable storage engines (i.e. Hash, B+Tree, R+Tree, LSM, etc.). - * The storage engine works with key/value pairs where both the key - * and the value are byte arrays of arbitrary length and with no restrictions on content. - * UnQLite come with two built-in KV storage engine: A Virtual Linear Hash (VLH) storage - * engine is used for persistent on-disk databases with O(1) lookup time and an in-memory - * hash-table or Red-black tree storage engine is used for in-memory databases. - * Future versions of UnQLite might add other built-in storage engines (i.e. LSM). - * Registration of a Key/Value storage engine at run-time is done via [unqlite_lib_config()] - * with a configuration verb set to UNQLITE_LIB_CONFIG_STORAGE_ENGINE. - */ -struct unqlite_kv_engine -{ - const unqlite_kv_io *pIo; /* IO methods: MUST be first */ - /* Subclasses will typically add additional fields */ -}; -/* - * Key/Value Storage Engine Virtual Method Table. - * - * Key/Value storage engine methods is defined by an instance of the following - * object. - * Registration of a Key/Value storage engine at run-time is done via [unqlite_lib_config()] - * with a configuration verb set to UNQLITE_LIB_CONFIG_STORAGE_ENGINE. - */ -struct unqlite_kv_methods -{ - const char *zName; /* Storage engine name [i.e. Hash, B+tree, LSM, R-tree, Mem, etc.]*/ - int szKv; /* 'unqlite_kv_engine' subclass size */ - int szCursor; /* 'unqlite_kv_cursor' subclass size */ - int iVersion; /* Structure version, currently 1 */ - /* Storage engine methods */ - int (*xInit)(unqlite_kv_engine *,int iPageSize); - void (*xRelease)(unqlite_kv_engine *); - int (*xConfig)(unqlite_kv_engine *,int op,va_list ap); - int (*xOpen)(unqlite_kv_engine *,pgno); - int (*xReplace)( - unqlite_kv_engine *, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ); - int (*xAppend)( - unqlite_kv_engine *, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ); - void (*xCursorInit)(unqlite_kv_cursor *); - int (*xSeek)(unqlite_kv_cursor *,const void *pKey,int nByte,int iPos); /* Mandatory */ - int (*xFirst)(unqlite_kv_cursor *); - int (*xLast)(unqlite_kv_cursor *); - int (*xValid)(unqlite_kv_cursor *); - int (*xNext)(unqlite_kv_cursor *); - int (*xPrev)(unqlite_kv_cursor *); - int (*xDelete)(unqlite_kv_cursor *); - int (*xKeyLength)(unqlite_kv_cursor *,int *); - int (*xKey)(unqlite_kv_cursor *,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); - int (*xDataLength)(unqlite_kv_cursor *,unqlite_int64 *); - int (*xData)(unqlite_kv_cursor *,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); - void (*xReset)(unqlite_kv_cursor *); - void (*xCursorRelease)(unqlite_kv_cursor *); -}; -/* - * UnQLite journal file suffix. - */ -#ifndef UNQLITE_JOURNAL_FILE_SUFFIX -#define UNQLITE_JOURNAL_FILE_SUFFIX "_unqlite_journal" -#endif -/* - * Call Context - Error Message Serverity Level. - * - * The following constans are the allowed severity level that can - * passed as the second argument to the [unqlite_context_throw_error()] or - * [unqlite_context_throw_error_format()] interfaces. - * Refer to the official documentation for additional information. - */ -#define UNQLITE_CTX_ERR 1 /* Call context error such as unexpected number of arguments, invalid types and so on. */ -#define UNQLITE_CTX_WARNING 2 /* Call context Warning */ -#define UNQLITE_CTX_NOTICE 3 /* Call context Notice */ -/* - * C-API-REF: Please refer to the official documentation for interfaces - * purpose and expected parameters. - */ - -/* Database Engine Handle */ -UNQLITE_APIEXPORT int unqlite_open(unqlite **ppDB,const char *zFilename,unsigned int iMode); -UNQLITE_APIEXPORT int unqlite_config(unqlite *pDb,int nOp,...); -UNQLITE_APIEXPORT int unqlite_close(unqlite *pDb); - - -/* Key/Value (KV) Store Interfaces */ -UNQLITE_APIEXPORT int unqlite_kv_store(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen); -UNQLITE_APIEXPORT int unqlite_kv_append(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen); -UNQLITE_APIEXPORT int unqlite_kv_store_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...); -UNQLITE_APIEXPORT int unqlite_kv_append_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...); -UNQLITE_APIEXPORT int unqlite_kv_fetch(unqlite *pDb,const void *pKey,int nKeyLen,void *pBuf,unqlite_int64 /* in|out */*pBufLen); -UNQLITE_APIEXPORT int unqlite_kv_fetch_callback(unqlite *pDb,const void *pKey, - int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_kv_delete(unqlite *pDb,const void *pKey,int nKeyLen); -UNQLITE_APIEXPORT int unqlite_kv_config(unqlite *pDb,int iOp,...); - -/* Document (JSON) Store Interfaces powered by the Jx9 Scripting Language */ -UNQLITE_APIEXPORT int unqlite_compile(unqlite *pDb,const char *zJx9,int nByte,unqlite_vm **ppOut); -UNQLITE_APIEXPORT int unqlite_compile_file(unqlite *pDb,const char *zPath,unqlite_vm **ppOut); -UNQLITE_APIEXPORT int unqlite_vm_config(unqlite_vm *pVm,int iOp,...); -UNQLITE_APIEXPORT int unqlite_vm_exec(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_reset(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_release(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_dump(unqlite_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData); -UNQLITE_APIEXPORT unqlite_value * unqlite_vm_extract_variable(unqlite_vm *pVm,const char *zVarname); - -/* Cursor Iterator Interfaces */ -UNQLITE_APIEXPORT int unqlite_kv_cursor_init(unqlite *pDb,unqlite_kv_cursor **ppOut); -UNQLITE_APIEXPORT int unqlite_kv_cursor_release(unqlite *pDb,unqlite_kv_cursor *pCur); -UNQLITE_APIEXPORT int unqlite_kv_cursor_seek(unqlite_kv_cursor *pCursor,const void *pKey,int nKeyLen,int iPos); -UNQLITE_APIEXPORT int unqlite_kv_cursor_first_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_last_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_valid_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_next_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_prev_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_key(unqlite_kv_cursor *pCursor,void *pBuf,int *pnByte); -UNQLITE_APIEXPORT int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_kv_cursor_data(unqlite_kv_cursor *pCursor,void *pBuf,unqlite_int64 *pnData); -UNQLITE_APIEXPORT int unqlite_kv_cursor_data_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_kv_cursor_delete_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_reset(unqlite_kv_cursor *pCursor); - -/* Manual Transaction Manager */ -UNQLITE_APIEXPORT int unqlite_begin(unqlite *pDb); -UNQLITE_APIEXPORT int unqlite_commit(unqlite *pDb); -UNQLITE_APIEXPORT int unqlite_rollback(unqlite *pDb); - -/* Utility interfaces */ -UNQLITE_APIEXPORT int unqlite_util_load_mmaped_file(const char *zFile,void **ppMap,unqlite_int64 *pFileSize); -UNQLITE_APIEXPORT int unqlite_util_release_mmaped_file(void *pMap,unqlite_int64 iFileSize); -UNQLITE_APIEXPORT int unqlite_util_random_string(unqlite *pDb,char *zBuf,unsigned int buf_size); -UNQLITE_APIEXPORT unsigned int unqlite_util_random_num(unqlite *pDb); - -/* In-process extending interfaces */ -UNQLITE_APIEXPORT int unqlite_create_function(unqlite_vm *pVm,const char *zName,int (*xFunc)(unqlite_context *,int,unqlite_value **),void *pUserData); -UNQLITE_APIEXPORT int unqlite_delete_function(unqlite_vm *pVm, const char *zName); -UNQLITE_APIEXPORT int unqlite_create_constant(unqlite_vm *pVm,const char *zName,void (*xExpand)(unqlite_value *, void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_delete_constant(unqlite_vm *pVm, const char *zName); - -/* On Demand Object allocation interfaces */ -UNQLITE_APIEXPORT unqlite_value * unqlite_vm_new_scalar(unqlite_vm *pVm); -UNQLITE_APIEXPORT unqlite_value * unqlite_vm_new_array(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_release_value(unqlite_vm *pVm,unqlite_value *pValue); -UNQLITE_APIEXPORT unqlite_value * unqlite_context_new_scalar(unqlite_context *pCtx); -UNQLITE_APIEXPORT unqlite_value * unqlite_context_new_array(unqlite_context *pCtx); -UNQLITE_APIEXPORT void unqlite_context_release_value(unqlite_context *pCtx,unqlite_value *pValue); - -/* Dynamically Typed Value Object Management Interfaces */ -UNQLITE_APIEXPORT int unqlite_value_int(unqlite_value *pVal, int iValue); -UNQLITE_APIEXPORT int unqlite_value_int64(unqlite_value *pVal, unqlite_int64 iValue); -UNQLITE_APIEXPORT int unqlite_value_bool(unqlite_value *pVal, int iBool); -UNQLITE_APIEXPORT int unqlite_value_null(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_double(unqlite_value *pVal, double Value); -UNQLITE_APIEXPORT int unqlite_value_string(unqlite_value *pVal, const char *zString, int nLen); -UNQLITE_APIEXPORT int unqlite_value_string_format(unqlite_value *pVal, const char *zFormat,...); -UNQLITE_APIEXPORT int unqlite_value_reset_string_cursor(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_resource(unqlite_value *pVal, void *pUserData); -UNQLITE_APIEXPORT int unqlite_value_release(unqlite_value *pVal); - -/* Foreign Function Parameter Values */ -UNQLITE_APIEXPORT int unqlite_value_to_int(unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_value_to_bool(unqlite_value *pValue); -UNQLITE_APIEXPORT unqlite_int64 unqlite_value_to_int64(unqlite_value *pValue); -UNQLITE_APIEXPORT double unqlite_value_to_double(unqlite_value *pValue); -UNQLITE_APIEXPORT const char * unqlite_value_to_string(unqlite_value *pValue, int *pLen); -UNQLITE_APIEXPORT void * unqlite_value_to_resource(unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_value_compare(unqlite_value *pLeft, unqlite_value *pRight, int bStrict); - -/* Setting The Result Of A Foreign Function */ -UNQLITE_APIEXPORT int unqlite_result_int(unqlite_context *pCtx, int iValue); -UNQLITE_APIEXPORT int unqlite_result_int64(unqlite_context *pCtx, unqlite_int64 iValue); -UNQLITE_APIEXPORT int unqlite_result_bool(unqlite_context *pCtx, int iBool); -UNQLITE_APIEXPORT int unqlite_result_double(unqlite_context *pCtx, double Value); -UNQLITE_APIEXPORT int unqlite_result_null(unqlite_context *pCtx); -UNQLITE_APIEXPORT int unqlite_result_string(unqlite_context *pCtx, const char *zString, int nLen); -UNQLITE_APIEXPORT int unqlite_result_string_format(unqlite_context *pCtx, const char *zFormat, ...); -UNQLITE_APIEXPORT int unqlite_result_value(unqlite_context *pCtx, unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_result_resource(unqlite_context *pCtx, void *pUserData); - -/* Dynamically Typed Value Object Query Interfaces */ -UNQLITE_APIEXPORT int unqlite_value_is_int(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_float(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_bool(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_string(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_null(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_numeric(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_callable(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_scalar(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_json_array(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_json_object(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_resource(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_empty(unqlite_value *pVal); - -/* JSON Array/Object Management Interfaces */ -UNQLITE_APIEXPORT unqlite_value * unqlite_array_fetch(unqlite_value *pArray, const char *zKey, int nByte); -UNQLITE_APIEXPORT int unqlite_array_walk(unqlite_value *pArray, int (*xWalk)(unqlite_value *, unqlite_value *, void *), void *pUserData); -UNQLITE_APIEXPORT int unqlite_array_add_elem(unqlite_value *pArray, unqlite_value *pKey, unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_array_add_strkey_elem(unqlite_value *pArray, const char *zKey, unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_array_count(unqlite_value *pArray); - -/* Call Context Handling Interfaces */ -UNQLITE_APIEXPORT int unqlite_context_output(unqlite_context *pCtx, const char *zString, int nLen); -UNQLITE_APIEXPORT int unqlite_context_output_format(unqlite_context *pCtx,const char *zFormat, ...); -UNQLITE_APIEXPORT int unqlite_context_throw_error(unqlite_context *pCtx, int iErr, const char *zErr); -UNQLITE_APIEXPORT int unqlite_context_throw_error_format(unqlite_context *pCtx, int iErr, const char *zFormat, ...); -UNQLITE_APIEXPORT unsigned int unqlite_context_random_num(unqlite_context *pCtx); -UNQLITE_APIEXPORT int unqlite_context_random_string(unqlite_context *pCtx, char *zBuf, int nBuflen); -UNQLITE_APIEXPORT void * unqlite_context_user_data(unqlite_context *pCtx); -UNQLITE_APIEXPORT int unqlite_context_push_aux_data(unqlite_context *pCtx, void *pUserData); -UNQLITE_APIEXPORT void * unqlite_context_peek_aux_data(unqlite_context *pCtx); -UNQLITE_APIEXPORT unsigned int unqlite_context_result_buf_length(unqlite_context *pCtx); -UNQLITE_APIEXPORT const char * unqlite_function_name(unqlite_context *pCtx); - -/* Call Context Memory Management Interfaces */ -UNQLITE_APIEXPORT void * unqlite_context_alloc_chunk(unqlite_context *pCtx,unsigned int nByte,int ZeroChunk,int AutoRelease); -UNQLITE_APIEXPORT void * unqlite_context_realloc_chunk(unqlite_context *pCtx,void *pChunk,unsigned int nByte); -UNQLITE_APIEXPORT void unqlite_context_free_chunk(unqlite_context *pCtx,void *pChunk); - -/* Global Library Management Interfaces */ -UNQLITE_APIEXPORT int unqlite_lib_config(int nConfigOp,...); -UNQLITE_APIEXPORT int unqlite_lib_init(void); -UNQLITE_APIEXPORT int unqlite_lib_shutdown(void); -UNQLITE_APIEXPORT int unqlite_lib_is_threadsafe(void); -UNQLITE_APIEXPORT const char * unqlite_lib_version(void); -UNQLITE_APIEXPORT const char * unqlite_lib_signature(void); -UNQLITE_APIEXPORT const char * unqlite_lib_ident(void); -UNQLITE_APIEXPORT const char * unqlite_lib_copyright(void); - -#endif /* _UNQLITE_H_ */ diff --git a/libs/libblade/src/ks_bencode.c b/libs/libblade/src/ks_bencode.c deleted file mode 100644 index b3ffc36bc6..0000000000 --- a/libs/libblade/src/ks_bencode.c +++ /dev/null @@ -1,2698 +0,0 @@ -/* - * libbencodetools - * - * Written by Heikki Orsila and - * Janne Kulmala in 2011. - */ -/* -Copyright (C) 2002-2005 Bram Cohen and Ross Cohen - -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. -* 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. -* Neither the name of Codeville 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 - -#include -#include -#include -#include -#include -#include -#include - -#define die(fmt, ...) /*fprintf(stderr, "bencode: fatal error: " fmt, __VA_ARGS__ ); abort()*/ abort() -#define warn(fmt, ...) /*fprintf(stderr, "bencode: warning: " fmt, __VA_ARGS__ )*/ - -#define MAX_ALLOC (((size_t) -1) / sizeof(struct bencode *) / 2) -#define DICT_MAX_ALLOC (((size_t) -1) / sizeof(struct bencode_dict_node) / 2) - -struct ben_decode_ctx { - const char *data; - const size_t len; - size_t off; - int error; - int level; - char c; - int line; - struct bencode_type **types; -}; - -struct ben_encode_ctx { - char *data; - size_t size; - size_t pos; -}; - -/* - * Buffer size for fitting all unsigned long long and long long integers, - * assuming it is at most 64 bits. If long long is larger than 64 bits, - * an error is produced when too large an integer is converted. - */ -#define LONGLONGSIZE 21 - -static struct bencode *decode_printed(struct ben_decode_ctx *ctx); -static void inplace_ben_str(struct bencode_str *b, const char *s, size_t len); -static int resize_dict(struct bencode_dict *d, size_t newalloc); -static int resize_list(struct bencode_list *list, size_t newalloc); -static int unpack(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl); -static struct bencode *pack(struct ben_decode_ctx *ctx, va_list *vl); - -static size_t type_size(int type) -{ - switch (type) { - case BENCODE_BOOL: - return sizeof(struct bencode_bool); - case BENCODE_DICT: - return sizeof(struct bencode_dict); - case BENCODE_INT: - return sizeof(struct bencode_int); - case BENCODE_LIST: - return sizeof(struct bencode_list); - case BENCODE_STR: - return sizeof(struct bencode_str); - default: - die("Unknown type: %d\n", type); - } -} - -static void *alloc(int type) -{ - struct bencode *b = calloc(1, type_size(type)); - if (b == NULL) - return NULL; - b->type = type; - return b; -} - -void *ben_alloc_user(struct bencode_type *type) -{ - struct bencode_user *user = calloc(1, type->size); - if (user == NULL) - return NULL; - user->type = BENCODE_USER; - user->info = type; - return user; -} - -static int insufficient(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INSUFFICIENT; - return -1; -} - -static int invalid(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INVALID; - return -1; -} - -static int mismatch(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_MISMATCH; - return -1; -} - -void *ben_insufficient_ptr(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INSUFFICIENT; - return NULL; -} - -void *ben_invalid_ptr(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_INVALID; - return NULL; -} - -void *ben_oom_ptr(struct ben_decode_ctx *ctx) -{ - ctx->error = BEN_NO_MEMORY; - return NULL; -} - -int ben_need_bytes(const struct ben_decode_ctx *ctx, size_t n) -{ - return ((ctx->off + n) <= ctx->len) ? 0 : -1; -} - -char ben_current_char(const struct ben_decode_ctx *ctx) -{ - return ctx->data[ctx->off]; -} - -const char *ben_current_buf(const struct ben_decode_ctx *ctx, size_t n) -{ - return ben_need_bytes(ctx, n) ? NULL : ctx->data + ctx->off; -} - -void ben_skip(struct ben_decode_ctx *ctx, size_t n) -{ - ctx->off += n; -} - -static struct bencode *internal_blob(void *data, size_t len) -{ - struct bencode_str *b = alloc(BENCODE_STR); - if (b == NULL) - return NULL; - b->s = data; - b->len = len; - assert(b->s[len] == 0); - return (struct bencode *) b; -} - -static void skip_to_next_line(struct ben_decode_ctx *ctx) -{ - for (; ctx->off < ctx->len; ctx->off++) { - if (ben_current_char(ctx) == '\n') { - ctx->line++; - ctx->off++; - break; - } - } -} - -static int seek_char(struct ben_decode_ctx *ctx) -{ - while (ctx->off < ctx->len) { - char c = ben_current_char(ctx); - if (isspace(c)) { - if (c == '\n') - ctx->line++; - ctx->off++; - } else if (c == '#') { - /* Skip comment */ - ctx->off++; - skip_to_next_line(ctx); - } else { - return 0; - } - } - return insufficient(ctx); -} - -/* - * Test if string 's' is located at current position. - * Increment current position and return 0 if the string matches. - * Returns -1 otherwise. The function avoids buffer overflow. - */ -static int try_match(struct ben_decode_ctx *ctx, const char *s) -{ - size_t n = strlen(s); - if (ben_need_bytes(ctx, n)) - return -1; - if (memcmp(ctx->data + ctx->off, s, n) != 0) - return -1; - ctx->off += n; - return 0; -} - -static int try_match_with_errors(struct ben_decode_ctx *ctx, const char *s) -{ - size_t n = strlen(s); - size_t left = ctx->len - ctx->off; - - assert(ctx->off <= ctx->len); - - if (left == 0) - return insufficient(ctx); - - if (left < n) { - if (memcmp(ctx->data + ctx->off, s, left) != 0) - return invalid(ctx); - return insufficient(ctx); - } - - if (memcmp(ctx->data + ctx->off, s, n) != 0) - return invalid(ctx); - - ctx->off += n; - return 0; -} - -int ben_allocate(struct bencode *b, size_t n) -{ - switch (b->type) { - case BENCODE_DICT: - return resize_dict(ben_dict_cast(b), n); - case BENCODE_LIST: - return resize_list(ben_list_cast(b), n); - default: - die("ben_allocate(): Unknown type %d\n", b->type); - } -} - -static struct bencode *clone_dict(const struct bencode_dict *d) -{ - struct bencode *key; - struct bencode *value; - struct bencode *newkey; - struct bencode *newvalue; - size_t pos; - struct bencode *newdict = ben_dict(); - if (newdict == NULL) - return NULL; - ben_dict_for_each(key, value, pos, (const struct bencode *) d) { - newkey = ben_clone(key); - newvalue = ben_clone(value); - if (newkey == NULL || newvalue == NULL) { - ben_free(newkey); - ben_free(newvalue); - goto error; - } - if (ben_dict_set(newdict, newkey, newvalue)) { - ben_free(newkey); - ben_free(newvalue); - goto error; - } - newkey = NULL; - newvalue = NULL; - } - return newdict; - -error: - ben_free(newdict); - return NULL; -} - -static struct bencode *clone_list(const struct bencode_list *list) -{ - struct bencode *value; - struct bencode *newvalue; - size_t pos; - struct bencode *newlist = ben_list(); - if (newlist == NULL) - return NULL; - ben_list_for_each(value, pos, (const struct bencode *) list) { - newvalue = ben_clone(value); - if (newvalue == NULL) - goto error; - if (ben_list_append(newlist, newvalue)) { - ben_free(newvalue); - goto error; - } - newvalue = NULL; - } - return newlist; - -error: - ben_free(newlist); - return NULL; -} - -static struct bencode *clone_str(const struct bencode_str *s) -{ - return ben_blob(s->s, s->len); -} - -static struct bencode *share_dict(const struct bencode_dict *d) -{ - struct bencode *newdict = ben_dict(); - if (newdict == NULL) - return NULL; - memcpy(newdict, d, sizeof(*d)); - ((struct bencode_dict *) newdict)->shared = 1; - return newdict; -} - -static struct bencode *share_list(const struct bencode_list *list) -{ - struct bencode *newlist = ben_list(); - if (newlist == NULL) - return NULL; - memcpy(newlist, list, sizeof(*list)); - ((struct bencode_list *) newlist)->shared = 1; - return newlist; -} - -struct bencode *ben_clone(const struct bencode *b) -{ - switch (b->type) { - case BENCODE_BOOL: - return ben_bool(ben_bool_const_cast(b)->b); - case BENCODE_DICT: - return clone_dict(ben_dict_const_cast(b)); - case BENCODE_INT: - return ben_int(ben_int_const_cast(b)->ll); - case BENCODE_LIST: - return clone_list(ben_list_const_cast(b)); - case BENCODE_STR: - return clone_str(ben_str_const_cast(b)); - default: - die("Invalid type %c\n", b->type); - } -} - -struct bencode *ben_shared_clone(const struct bencode *b) -{ - switch (b->type) { - case BENCODE_DICT: - return share_dict(ben_dict_const_cast(b)); - break; - case BENCODE_LIST: - return share_list(ben_list_const_cast(b)); - break; - default: - return ben_clone(b); - } -} - -static int cmp_dict(const struct bencode *a, const struct bencode *b) -{ - size_t len = ben_dict_len(a); - size_t pos; - struct bencode *key; - struct bencode *va; - struct bencode *vb; - int ret = 0; - struct bencode_keyvalue *pairs; - - if (len != ben_dict_len(b)) { - /* Returning any non-zero value is allowed */ - return (len < ben_dict_len(b)) ? -1 : 1; - } - - pairs = ben_dict_ordered_items(a); - for (pos = 0; pos < len; pos++) { - key = pairs[pos].key; - va = pairs[pos].value; - vb = ben_dict_get(b, key); - if (vb == NULL) { - /* Returning any non-zero value is allowed */ - ret = (a < b) ? -1 : 1; - break; - } - ret = ben_cmp(va, vb); - if (ret) - break; - } - - free(pairs); - return ret; -} - -static int cmp_list(const struct bencode *a, const struct bencode *b) -{ - const struct bencode_list *la; - const struct bencode_list *lb; - struct bencode *va; - struct bencode *vb; - size_t cmplen; - size_t i; - int ret; - - la = ben_list_const_cast(a); - lb = ben_list_const_cast(b); - cmplen = (la->n <= lb->n) ? la->n : lb->n; - - for (i = 0; i < cmplen; ++i) { - va = ben_list_get(a, i); - vb = ben_list_get(b, i); - ret = ben_cmp(va, vb); - if (ret) - return ret; - } - if (la->n != lb->n) - return (la->n < lb->n) ? -1 : 1; - return 0; -} - -int ben_cmp(const struct bencode *a, const struct bencode *b) -{ - size_t cmplen; - int ret; - const struct bencode_int *ia; - const struct bencode_int *ib; - const struct bencode_str *sa; - const struct bencode_str *sb; - const struct bencode_user *ua; - const struct bencode_user *ub; - - if (a->type != b->type) - return (a->type == BENCODE_INT) ? -1 : 1; - - switch (a->type) { - case BENCODE_INT: - ia = ben_int_const_cast(a); - ib = ben_int_const_cast(b); - if (ia->ll < ib->ll) - return -1; - if (ib->ll < ia->ll) - return 1; - return 0; - case BENCODE_STR: - sa = ben_str_const_cast(a); - sb = ben_str_const_cast(b); - cmplen = (sa->len <= sb->len) ? sa->len : sb->len; - ret = memcmp(sa->s, sb->s, cmplen); - if (ret) - return ret < 0 ? -1 : 1; - if (sa->len != sb->len) - return (sa->len < sb->len) ? -1 : 1; - return 0; - case BENCODE_DICT: - return cmp_dict(a, b); - case BENCODE_LIST: - return cmp_list(a, b); - case BENCODE_USER: - ua = ben_user_const_cast(a); - ub = ben_user_const_cast(b); - if (ua->info != ub->info) - return (a < b) ? -1 : 1; - return ua->info->cmp(a, b); - default: - die("Invalid type %c\n", b->type); - } -} - -int ben_cmp_with_str(const struct bencode *a, const char *s) -{ - struct bencode_str b; - inplace_ben_str(&b, s, strlen(s)); - return ben_cmp(a, (struct bencode *) &b); -} - -int ben_cmp_qsort(const void *a, const void *b) -{ - const struct bencode *akey = ((const struct bencode_keyvalue *) a)->key; - const struct bencode *bkey = ((const struct bencode_keyvalue *) b)->key; - return ben_cmp(akey, bkey); -} - -static struct bencode *decode_bool(struct ben_decode_ctx *ctx) -{ - struct bencode_bool *b; - char value; - char c; - if (ben_need_bytes(ctx, 2)) - return ben_insufficient_ptr(ctx); - ctx->off++; - - c = ben_current_char(ctx); - if (c != '0' && c != '1') - return ben_invalid_ptr(ctx); - - value = (c == '1'); - b = alloc(BENCODE_BOOL); - if (b == NULL) - return ben_oom_ptr(ctx); - - b->b = value; - ctx->off++; - return (struct bencode *) b; -} - -static size_t hash_bucket(long long hash, const struct bencode_dict *d) -{ - return hash & (d->alloc - 1); -} - -static size_t hash_bucket_head(long long hash, const struct bencode_dict *d) -{ - if (d->buckets == NULL) - return -1; - return d->buckets[hash_bucket(hash, d)]; -} - -static int resize_dict(struct bencode_dict *d, size_t newalloc) -{ - size_t *newbuckets; - struct bencode_dict_node *newnodes;; - size_t pos; - - if (newalloc == -1) { - if (d->alloc >= DICT_MAX_ALLOC) - return -1; - - if (d->alloc == 0) - newalloc = 4; - else - newalloc = d->alloc * 2; - } else { - size_t x; - if (newalloc < d->n || newalloc > DICT_MAX_ALLOC) - return -1; - /* Round to next power of two */ - x = 1; - while (x < newalloc) - x <<= 1; - assert(x >= newalloc); - newalloc = x; - if (newalloc > DICT_MAX_ALLOC) - return -1; - } - - /* size must be a power of two */ - assert((newalloc & (newalloc - 1)) == 0); - - newbuckets = realloc(d->buckets, sizeof(newbuckets[0]) * newalloc); - newnodes = realloc(d->nodes, sizeof(newnodes[0]) * newalloc); - if (newnodes == NULL || newbuckets == NULL) { - free(newnodes); - free(newbuckets); - return -1; - } - - d->alloc = newalloc; - d->buckets = newbuckets; - d->nodes = newnodes; - - /* Clear all buckets */ - memset(d->buckets, -1, d->alloc * sizeof(d->buckets[0])); - - /* Reinsert nodes into buckets */ - for (pos = 0; pos < d->n; pos++) { - struct bencode_dict_node *node = &d->nodes[pos]; - size_t bucket = hash_bucket(node->hash, d); - node->next = d->buckets[bucket]; - d->buckets[bucket] = pos; - } - - return 0; -} - -/* The string/binary object hash is copied from Python */ -static long long str_hash(const unsigned char *s, size_t len) -{ - long long hash; - size_t i; - if (len == 0) - return 0; - hash = s[0] << 7; - for (i = 0; i < len; i++) - hash = (1000003 * hash) ^ s[i]; - hash ^= len; - if (hash == -1) - hash = -2; - return hash; -} - -long long ben_str_hash(const struct bencode *b) -{ - const struct bencode_str *bstr = ben_str_const_cast(b); - const unsigned char *s = (unsigned char *) bstr->s; - return str_hash(s, bstr->len); -} - -long long ben_int_hash(const struct bencode *b) -{ - long long x = ben_int_const_cast(b)->ll; - return (x == -1) ? -2 : x; -} - -long long ben_hash(const struct bencode *b) -{ - switch (b->type) { - case BENCODE_INT: - return ben_int_hash(b); - case BENCODE_STR: - return ben_str_hash(b); - default: - die("hash: Invalid type: %d\n", b->type); - } -} - -static struct bencode *decode_dict(struct ben_decode_ctx *ctx) -{ - struct bencode *key; - struct bencode *lastkey = NULL; - struct bencode *value; - struct bencode_dict *d; - - d = alloc(BENCODE_DICT); - if (d == NULL) { - //warn("Not enough memory for dict\n"); - return ben_oom_ptr(ctx); - } - - ctx->off++; - - while (ctx->off < ctx->len && ben_current_char(ctx) != 'e') { - key = ben_ctx_decode(ctx); - if (key == NULL) - goto error; - if (key->type != BENCODE_INT && key->type != BENCODE_STR) { - ben_free(key); - key = NULL; - ctx->error = BEN_INVALID; - //warn("Invalid dict key type\n"); - goto error; - } - - if (lastkey != NULL && ben_cmp(lastkey, key) >= 0) { - ben_free(key); - key = NULL; - ctx->error = BEN_INVALID; - goto error; - } - - value = ben_ctx_decode(ctx); - if (value == NULL) { - ben_free(key); - key = NULL; - goto error; - } - - if (ben_dict_set((struct bencode *) d, key, value)) { - ben_free(key); - ben_free(value); - key = NULL; - value = NULL; - ctx->error = BEN_NO_MEMORY; - goto error; - } - - lastkey = key; - } - if (ctx->off >= ctx->len) { - ctx->error = BEN_INSUFFICIENT; - goto error; - } - - ctx->off++; - - return (struct bencode *) d; - -error: - ben_free((struct bencode *) d); - return NULL; -} - -static size_t find(const struct ben_decode_ctx *ctx, char c) -{ - char *match = memchr(ctx->data + ctx->off, c, ctx->len - ctx->off); - if (match == NULL) - return -1; - return (size_t) (match - ctx->data); -} - -/* off is the position of first number in */ -static int read_long_long(long long *ll, struct ben_decode_ctx *ctx, int c) -{ - char buf[LONGLONGSIZE]; /* fits all 64 bit integers */ - char *endptr; - size_t slen; - size_t pos = find(ctx, c); - - if (pos == -1) - return insufficient(ctx); - - slen = pos - ctx->off; - if (slen == 0 || slen >= sizeof buf) - return invalid(ctx); - - assert(slen < sizeof buf); - memcpy(buf, ctx->data + ctx->off, slen); - buf[slen] = 0; - - if (buf[0] != '-' && !isdigit(buf[0])) - return invalid(ctx); - - errno = 0; - *ll = strtoll(buf, &endptr, 10); - if (errno == ERANGE || *endptr != 0) - return invalid(ctx); - - /* - * Demand a unique encoding for all integers. - * Zero may not begin with a (minus) sign. - * Non-zero integers may not have leading zeros in the encoding. - */ - if (buf[0] == '-' && buf[1] == '0') - return invalid(ctx); - if (buf[0] == '0' && pos != (ctx->off + 1)) - return invalid(ctx); - - ctx->off = pos + 1; - return 0; -} - -static struct bencode *decode_int(struct ben_decode_ctx *ctx) -{ - struct bencode_int *b; - long long ll; - ctx->off++; - if (read_long_long(&ll, ctx, 'e')) - return NULL; - b = alloc(BENCODE_INT); - if (b == NULL) - return ben_oom_ptr(ctx); - b->ll = ll; - return (struct bencode *) b; -} - -static int resize_list(struct bencode_list *list, size_t newalloc) -{ - struct bencode **newvalues; - size_t newsize; - - if (newalloc == -1) { - if (list->alloc >= MAX_ALLOC) - return -1; - if (list->alloc == 0) - newalloc = 4; - else - newalloc = list->alloc * 2; - } else { - if (newalloc < list->n || newalloc > MAX_ALLOC) - return -1; - } - - newsize = sizeof(list->values[0]) * newalloc; - newvalues = realloc(list->values, newsize); - if (newvalues == NULL) - return -1; - list->alloc = newalloc; - list->values = newvalues; - return 0; -} - -static struct bencode *decode_list(struct ben_decode_ctx *ctx) -{ - struct bencode_list *l = alloc(BENCODE_LIST); - if (l == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (ctx->off < ctx->len && ben_current_char(ctx) != 'e') { - struct bencode *b = ben_ctx_decode(ctx); - if (b == NULL) - goto error; - if (ben_list_append((struct bencode *) l, b)) { - ben_free(b); - ctx->error = BEN_NO_MEMORY; - goto error; - } - } - - if (ctx->off >= ctx->len) { - ctx->error = BEN_INSUFFICIENT; - goto error; - } - - ctx->off++; - return (struct bencode *) l; - -error: - ben_free((struct bencode *) l); - return NULL; -} - -static size_t read_size_t(struct ben_decode_ctx *ctx, int c) -{ - long long ll; - size_t s; - if (read_long_long(&ll, ctx, c)) - return -1; - if (ll < 0) - return invalid(ctx); - /* - * Test that information is not lost when converting from long long - * to size_t - */ - s = (size_t) ll; - if (ll != (long long) s) - return invalid(ctx); - return s; -} - -static struct bencode *decode_str(struct ben_decode_ctx *ctx) -{ - struct bencode *b; - size_t datalen = read_size_t(ctx, ':'); /* Read the string length */ - if (datalen == -1) - return NULL; - - if (ben_need_bytes(ctx, datalen)) - return ben_insufficient_ptr(ctx); - - /* Allocate string structure and copy data into it */ - b = ben_blob(ctx->data + ctx->off, datalen); - ctx->off += datalen; - return b; -} - -struct bencode *ben_ctx_decode(struct ben_decode_ctx *ctx) -{ - char c; - struct bencode_type *type; - struct bencode *b; - ctx->level++; - if (ctx->level > 256) - return ben_invalid_ptr(ctx); - - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - - assert (ctx->off < ctx->len); - c = ben_current_char(ctx); - switch (c) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - b = decode_str(ctx); - break; - case 'b': - b = decode_bool(ctx); - break; - case 'd': - b = decode_dict(ctx); - break; - case 'i': - b = decode_int(ctx); - break; - case 'l': - b = decode_list(ctx); - break; - default: - if (ctx->types && (unsigned char) c < 128) { - type = ctx->types[(unsigned char) c]; - if (type) { - ctx->off++; - b = type->decode(ctx); - } else - return ben_invalid_ptr(ctx); - } else - return ben_invalid_ptr(ctx); - } - ctx->level--; - return b; -} - -struct bencode *ben_decode(const void *data, size_t len) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len}; - struct bencode *b = ben_ctx_decode(&ctx); - if (b != NULL && ctx.off != len) { - ben_free(b); - return NULL; - } - return b; -} - -struct bencode *ben_decode2(const void *data, size_t len, size_t *off, int *error) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len, .off = *off}; - struct bencode *b = ben_ctx_decode(&ctx); - *off = ctx.off; - if (error != NULL) { - assert((b != NULL) ^ (ctx.error != 0)); - *error = ctx.error; - } - return b; -} - -struct bencode *ben_decode3(const void *data, size_t len, size_t *off, int *error, struct bencode_type *types[128]) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len, .off = *off, - .types = types}; - struct bencode *b = ben_ctx_decode(&ctx); - *off = ctx.off; - if (error != NULL) { - assert((b != NULL) ^ (ctx.error != 0)); - *error = ctx.error; - } - return b; -} - -static struct bencode *decode_printed_bool(struct ben_decode_ctx *ctx) -{ - struct bencode *b; - int bval = -1; - - if (try_match(ctx, "True")) { - if (ben_need_bytes(ctx, 4)) - return ben_insufficient_ptr(ctx); - } else { - bval = 1; - } - - if (bval < 0) { - /* It's not 'True', so it can only be 'False'. Verify it. */ - if (try_match_with_errors(ctx, "False")) - return NULL; - bval = 0; - } - - assert(bval == 0 || bval == 1); - b = ben_bool(bval); - if (b == NULL) - return ben_oom_ptr(ctx); - return b; -} - -static struct bencode *decode_printed_dict(struct ben_decode_ctx *ctx) -{ - struct bencode *d = ben_dict(); - struct bencode *key = NULL; - struct bencode *value = NULL; - - if (d == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == '}') { - ctx->off++; - break; - } - - key = decode_printed(ctx); - if (key == NULL) - goto nullpath; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) != ':') - goto invalidpath; - ctx->off++; - - value = decode_printed(ctx); - if (value == NULL) - goto nullpath; - - if (ben_dict_set(d, key, value)) { - ben_free(key); - ben_free(value); - ben_free(d); - return ben_oom_ptr(ctx); - } - key = NULL; - value = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != '}') - goto invalidpath; - } - return d; - -invalidpath: - ben_free(key); - ben_free(value); - ben_free(d); - return ben_invalid_ptr(ctx); - -nullpath: - ben_free(key); - ben_free(value); - ben_free(d); - return NULL; -} - -static struct bencode *decode_printed_int(struct ben_decode_ctx *ctx) -{ - long long ll; - char buf[LONGLONGSIZE]; - char *end; - size_t pos = 0; - struct bencode *b; - int gotzero = 0; - int base = 10; - int neg = 0; - - if (ben_current_char(ctx) == '-') { - neg = 1; - ctx->off++; - } - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - - if (ben_current_char(ctx) == '0') { - buf[pos] = '0'; - pos++; - ctx->off++; - gotzero = 1; - } - - if (gotzero) { - if (ctx->off == ctx->len) { - ll = 0; - goto returnwithval; - } - if (ben_current_char(ctx) == 'x') { - pos = 0; - base = 16; - ctx->off++; - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - } else if (isdigit(ben_current_char(ctx))) { - base = 8; - } - } else { - if (ctx->off == ctx->len) - return ben_insufficient_ptr(ctx); - } - - while (ctx->off < ctx->len && pos < sizeof buf) { - char c = ben_current_char(ctx); - if (base == 16) { - if (!isxdigit(c)) - break; - } else { - if (!isdigit(c)) - break; - } - buf[pos] = c; - pos++; - ctx->off++; - } - if (pos == 0 || pos == sizeof buf) - return ben_invalid_ptr(ctx); - buf[pos] = 0; - ll = strtoll(buf, &end, base); - if (*end != 0) - return ben_invalid_ptr(ctx); - -returnwithval: - if (neg) - ll = -ll; - b = ben_int(ll); - if (b == NULL) - return ben_oom_ptr(ctx); - return b; -} - -static struct bencode *decode_printed_list(struct ben_decode_ctx *ctx) -{ - struct bencode *l = ben_list(); - struct bencode *b = NULL; - - if (l == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ']') { - ctx->off++; - break; - } - b = decode_printed(ctx); - if (b == NULL) - goto nullpath; - if (ben_list_append(l, b)) { - ben_free(b); - ben_free(l); - return ben_oom_ptr(ctx); - } - b = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != ']') { - ben_free(l); - return ben_invalid_ptr(ctx); - } - } - return l; - -nullpath: - ben_free(b); - ben_free(l); - return NULL; -} - -static struct bencode *decode_printed_str(struct ben_decode_ctx *ctx) -{ - size_t pos; - char *s = NULL; - size_t len = 0; - char initial = ben_current_char(ctx); - struct bencode *b; - - ctx->off++; - pos = ctx->off; - while (pos < ctx->len) { - char c = ctx->data[pos]; - if (!isprint(c)) - return ben_invalid_ptr(ctx); - if (c == initial) - break; - len++; - pos++; - if (c != '\\') - continue; /* Normal printable char, e.g. 'a' */ - /* Handle '\\' */ - if (pos == ctx->len) - return ben_insufficient_ptr(ctx); - - c = ctx->data[pos]; - pos++; - if (c == 'x') { - /* hexadecimal value: \xHH */ - pos += 2; - } - } - if (pos >= ctx->len) - return ben_insufficient_ptr(ctx); - - s = malloc(len + 1); - if (s == NULL) - return ben_oom_ptr(ctx); - - pos = 0; - while (ctx->off < ctx->len) { - char c = ben_current_char(ctx); - assert(isprint(c)); - if (c == initial) - break; - assert(pos < len); - ctx->off++; - if (c != '\\') { - s[pos] = c; - pos++; - continue; /* Normal printable char, e.g. 'a' */ - } - /* Handle '\\' */ - - /* - * Note, we do assert because we have already verified in the - * previous loop that there is sufficient data. - */ - assert(ctx->off != ctx->len); - c = ben_current_char(ctx); - ctx->off++; - if (c == 'x') { - /* hexadecimal value: \xHH */ - char *end; - unsigned long x; - char buf[3]; - assert((ctx->off + 1) < ctx->len); - buf[0] = ctx->data[ctx->off + 0]; - buf[1] = ctx->data[ctx->off + 1]; - buf[2] = 0; - ctx->off += 2; - x = strtoul(buf, &end, 16); - if (*end != 0) - goto invalid; - assert(x < 256); - c = (char) x; - } - s[pos] = c; - pos++; - } - assert(pos == len); - if (ctx->off >= ctx->len) - return ben_insufficient_ptr(ctx); - ctx->off++; - - s[pos] = 0; /* the area must always be zero terminated! */ - - b = internal_blob(s, len); - if (b == NULL) { - free(s); - return ben_oom_ptr(ctx); - } - return b; - -invalid: - free(s); - return ben_invalid_ptr(ctx); -} - -static struct bencode *decode_printed(struct ben_decode_ctx *ctx) -{ - struct bencode *b; - - ctx->level++; - if (ctx->level > 256) - return ben_invalid_ptr(ctx); - - if (seek_char(ctx)) - return NULL; - - switch (ben_current_char(ctx)) { - case '\'': - case '"': - b = decode_printed_str(ctx); - break; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - b = decode_printed_int(ctx); - break; - case 'F': - case 'T': - b = decode_printed_bool(ctx); - break; - case '[': - b = decode_printed_list(ctx); - break; - case '{': - b = decode_printed_dict(ctx); - break; - default: - return ben_invalid_ptr(ctx); - } - ctx->level--; - return b; -} - -struct bencode *ben_decode_printed(const void *data, size_t len) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len}; - return decode_printed(&ctx); -} - -struct bencode *ben_decode_printed2(const void *data, size_t len, size_t *off, struct bencode_error *error) -{ - struct ben_decode_ctx ctx = {.data = data, .len = len, .off = *off}; - struct bencode *b = decode_printed(&ctx); - *off = ctx.off; - if (error != NULL) { - assert((b != NULL) ^ (ctx.error != 0)); - error->error = ctx.error; - if (b != NULL) { - error->off = 0; - error->line = 0; - } else { - error->off = ctx.off; - error->line = ctx.line; - } - } - return b; -} - -static void free_dict(struct bencode_dict *d) -{ - size_t pos; - if (d->shared) - return; - for (pos = 0; pos < d->n; pos++) { - ben_free(d->nodes[pos].key); - ben_free(d->nodes[pos].value); - d->nodes[pos].key = NULL; - d->nodes[pos].value = NULL; - } - free(d->buckets); - free(d->nodes); -} - -static void free_list(struct bencode_list *list) -{ - size_t pos; - if (list->shared) - return; - for (pos = 0; pos < list->n; pos++) { - ben_free(list->values[pos]); - list->values[pos] = NULL; - } - free(list->values); -} - -int ben_put_char(struct ben_encode_ctx *ctx, char c) -{ - if (ctx->pos >= ctx->size) - return -1; - ctx->data[ctx->pos] = c; - ctx->pos++; - return 0; -} - -int ben_put_buffer(struct ben_encode_ctx *ctx, const void *buf, size_t len) -{ - if ((ctx->pos + len) > ctx->size) - return -1; - memcpy(ctx->data + ctx->pos, buf, len); - ctx->pos += len; - return 0; -} - -static int puthexchar(struct ben_encode_ctx *ctx, unsigned char hex) -{ - char buf[5]; - int len = snprintf(buf, sizeof buf, "\\x%.2x", hex); - assert(len == 4); - return ben_put_buffer(ctx, buf, len); -} - -static int putlonglong(struct ben_encode_ctx *ctx, long long ll) -{ - char buf[LONGLONGSIZE]; - int len = snprintf(buf, sizeof buf, "%lld", ll); - assert(len > 0); - return ben_put_buffer(ctx, buf, len); -} - -static int putunsignedlonglong(struct ben_encode_ctx *ctx, unsigned long long llu) -{ - char buf[LONGLONGSIZE]; - int len = snprintf(buf, sizeof buf, "%llu", llu); - assert(len > 0); - return ben_put_buffer(ctx, buf, len); -} - -static int putstr(struct ben_encode_ctx *ctx, char *s) -{ - return ben_put_buffer(ctx, s, strlen(s)); -} - -static int print(struct ben_encode_ctx *ctx, const struct bencode *b) -{ - const struct bencode_bool *boolean; - const struct bencode_int *integer; - const struct bencode_list *list; - const struct bencode_str *s; - size_t i; - size_t len; - struct bencode_keyvalue *pairs; - - switch (b->type) { - case BENCODE_BOOL: - boolean = ben_bool_const_cast(b); - return putstr(ctx, boolean->b ? "True" : "False"); - - case BENCODE_DICT: - if (ben_put_char(ctx, '{')) - return -1; - - pairs = ben_dict_ordered_items(b); - if (pairs == NULL) { - //warn("No memory for dict serialization\n"); - return -1; - } - - len = ben_dict_len(b); - for (i = 0; i < len; i++) { - if (print(ctx, pairs[i].key)) - break; - if (putstr(ctx, ": ")) - break; - if (print(ctx, pairs[i].value)) - break; - if (i < (len - 1)) { - if (putstr(ctx, ", ")) - break; - } - } - free(pairs); - pairs = NULL; - if (i < len) - return -1; - - return ben_put_char(ctx, '}'); - - case BENCODE_INT: - integer = ben_int_const_cast(b); - - if (putlonglong(ctx, integer->ll)) - return -1; - - return 0; - - case BENCODE_LIST: - if (ben_put_char(ctx, '[')) - return -1; - list = ben_list_const_cast(b); - for (i = 0; i < list->n; i++) { - if (print(ctx, list->values[i])) - return -1; - if (i < (list->n - 1) && putstr(ctx, ", ")) - return -1; - } - return ben_put_char(ctx, ']'); - - case BENCODE_STR: - s = ben_str_const_cast(b); - if (ben_put_char(ctx, '\'')) - return -1; - for (i = 0; i < s->len; i++) { - if (!isprint(s->s[i])) { - if (puthexchar(ctx, s->s[i])) - return -1; - continue; - } - - switch (s->s[i]) { - case '\'': - case '\\': - /* Need escape character */ - if (ben_put_char(ctx, '\\')) - return -1; - default: - if (ben_put_char(ctx, s->s[i])) - return -1; - break; - } - } - return ben_put_char(ctx, '\''); - default: - die("serialization type %d not implemented\n", b->type); - } -} - -static size_t get_printed_size(const struct bencode *b) -{ - size_t pos; - const struct bencode_bool *boolean; - const struct bencode_dict *d; - const struct bencode_int *i; - const struct bencode_list *l; - const struct bencode_str *s; - size_t size = 0; - char buf[1]; - - switch (b->type) { - case BENCODE_BOOL: - boolean = ben_bool_const_cast(b); - return boolean->b ? 4 : 5; /* "True" and "False" */ - case BENCODE_DICT: - size++; /* "{" */ - d = ben_dict_const_cast(b); - for (pos = 0; pos < d->n; pos++) { - size += get_printed_size(d->nodes[pos].key); - size += 2; /* ": " */ - size += get_printed_size(d->nodes[pos].value); - if (pos < (d->n - 1)) - size += 2; /* ", " */ - } - size++; /* "}" */ - return size; - case BENCODE_INT: - i = ben_int_const_cast(b); - return snprintf(buf, 0, "%lld", i->ll); - case BENCODE_LIST: - size++; /* "[" */ - l = ben_list_const_cast(b); - for (pos = 0; pos < l->n; pos++) { - size += get_printed_size(l->values[pos]); - if (pos < (l->n - 1)) - size += 2; /* ", " */ - } - size++; /* "]" */ - return size; - case BENCODE_STR: - s = ben_str_const_cast(b); - size++; /* ' */ - for (pos = 0; pos < s->len; pos++) { - if (!isprint(s->s[pos])) { - size += 4; /* "\xDD" */ - continue; - } - switch (s->s[pos]) { - case '\'': - case '\\': - size += 2; /* escaped characters */ - break; - default: - size++; - break; - } - } - size++; /* ' */ - return size; - default: - die("Unknown type: %c\n", b->type); - } -} - -int ben_ctx_encode(struct ben_encode_ctx *ctx, const struct bencode *b) -{ - const struct bencode_bool *boolean; - const struct bencode_int *integer; - const struct bencode_list *list; - const struct bencode_str *s; - const struct bencode_user *u; - size_t i; - size_t len; - struct bencode_keyvalue *pairs; - - switch (b->type) { - case BENCODE_BOOL: - boolean = ben_bool_const_cast(b); - return putstr(ctx, boolean->b ? "b1" : "b0"); - - case BENCODE_DICT: - if (ben_put_char(ctx, 'd')) - return -1; - - pairs = ben_dict_ordered_items(b); - if (pairs == NULL) { - //warn("No memory for dict serialization\n"); - return -1; - } - - len = ben_dict_len(b); - for (i = 0; i < len; i++) { - if (ben_ctx_encode(ctx, pairs[i].key)) - break; - if (ben_ctx_encode(ctx, pairs[i].value)) - break; - } - free(pairs); - pairs = NULL; - if (i < len) - return -1; - - return ben_put_char(ctx, 'e'); - - case BENCODE_INT: - if (ben_put_char(ctx, 'i')) - return -1; - integer = ben_int_const_cast(b); - if (putlonglong(ctx, integer->ll)) - return -1; - return ben_put_char(ctx, 'e'); - - case BENCODE_LIST: - if (ben_put_char(ctx, 'l')) - return -1; - - list = ben_list_const_cast(b); - for (i = 0; i < list->n; i++) { - if (ben_ctx_encode(ctx, list->values[i])) - return -1; - } - - return ben_put_char(ctx, 'e'); - - case BENCODE_STR: - s = ben_str_const_cast(b); - if (putunsignedlonglong(ctx, ((long long) s->len))) - return -1; - if (ben_put_char(ctx, ':')) - return -1; - return ben_put_buffer(ctx, s->s, s->len); - - case BENCODE_USER: - u = ben_user_const_cast(b); - return u->info->encode(ctx, b); - - default: - die("serialization type %d not implemented\n", b->type); - } -} - -static size_t get_size(const struct bencode *b) -{ - size_t pos; - const struct bencode_dict *d; - const struct bencode_int *i; - const struct bencode_list *l; - const struct bencode_str *s; - const struct bencode_user *u; - size_t size = 0; - char buf[1]; - - switch (b->type) { - case BENCODE_BOOL: - return 2; - case BENCODE_DICT: - d = ben_dict_const_cast(b); - for (pos = 0; pos < d->n; pos++) { - size += get_size(d->nodes[pos].key); - size += get_size(d->nodes[pos].value); - } - return size + 2; - case BENCODE_INT: - i = ben_int_const_cast(b); - return 2 + snprintf(buf, 0, "%lld", i->ll); - case BENCODE_LIST: - l = ben_list_const_cast(b); - for (pos = 0; pos < l->n; pos++) - size += get_size(l->values[pos]); - return size + 2; - case BENCODE_STR: - s = ben_str_const_cast(b); - return snprintf(buf, 0, "%zu", s->len) + 1 + s->len; - case BENCODE_USER: - u = ben_user_const_cast(b); - return u->info->get_size(b); - default: - die("Unknown type: %c\n", b->type); - } -} - -size_t ben_encoded_size(const struct bencode *b) -{ - return get_size(b); -} - -void *ben_encode(size_t *len, const struct bencode *b) -{ - size_t size = get_size(b); - void *data = malloc(size + 1); - struct ben_encode_ctx ctx = {.data = data, .size = size}; - if (data == NULL) { - //warn("No memory to encode\n"); - return NULL; - } - if (ben_ctx_encode(&ctx, b)) { - free(ctx.data); - return NULL; - } - assert(ctx.pos == size); - ctx.data[size] = '\0'; - *len = ctx.pos; - return data; -} - -size_t ben_encode2(char *data, size_t maxlen, const struct bencode *b) -{ - struct ben_encode_ctx ctx = {.data = data, .size = maxlen, .pos = 0}; - if (ben_ctx_encode(&ctx, b)) - return -1; - return ctx.pos; -} - -void ben_free(struct bencode *b) -{ - struct bencode_str *s; - struct bencode_user *u; - size_t size; - if (b == NULL) - return; - switch (b->type) { - case BENCODE_BOOL: - break; - case BENCODE_DICT: - free_dict(ben_dict_cast(b)); - break; - case BENCODE_INT: - break; - case BENCODE_LIST: - free_list(ben_list_cast(b)); - break; - case BENCODE_STR: - s = ben_str_cast(b); - free(s->s); - break; - case BENCODE_USER: - u = ben_user_cast(b); - if (u->info->freer) - u->info->freer(b); - break; - default: - die("invalid type: %d\n", b->type); - } - - if (b->type == BENCODE_USER) - size = ((struct bencode_user *) b)->info->size; - else - size = type_size(b->type); - memset(b, -1, size); /* data poison */ - free(b); -} - -struct bencode *ben_blob(const void *data, size_t len) -{ - struct bencode_str *b = alloc(BENCODE_STR); - if (b == NULL) - return NULL; - /* Allocate one extra byte for zero termination for convenient use */ - b->s = malloc(len + 1); - if (b->s == NULL) { - free(b); - return NULL; - } - memcpy(b->s, data, len); - b->len = len; - b->s[len] = 0; - return (struct bencode *) b; -} - -struct bencode *ben_bool(int boolean) -{ - struct bencode_bool *b = alloc(BENCODE_BOOL); - if (b == NULL) - return NULL; - b->b = boolean ? 1 : 0; - return (struct bencode *) b; -} - -struct bencode *ben_dict(void) -{ - return alloc(BENCODE_DICT); -} - -struct bencode *ben_dict_get(const struct bencode *dict, const struct bencode *key) -{ - const struct bencode_dict *d = ben_dict_const_cast(dict); - long long hash = ben_hash(key); - size_t pos = hash_bucket_head(hash, d); - while (pos != -1) { - assert(pos < d->n); - if (d->nodes[pos].hash == hash && - ben_cmp(d->nodes[pos].key, key) == 0) - return d->nodes[pos].value; - pos = d->nodes[pos].next; - } - return NULL; -} - -/* - * Note, we do not re-allocate memory, so one may not call ben_free for these - * instances. These are only used to optimize speed. - */ -static void inplace_ben_str(struct bencode_str *b, const char *s, size_t len) -{ - b->type = BENCODE_STR; - b->len = len; - b->s = (char *) s; -} - -static void inplace_ben_int(struct bencode_int *i, long long ll) -{ - i->type = BENCODE_INT; - i->ll = ll; -} - -struct bencode *ben_dict_get_by_str(const struct bencode *dict, const char *key) -{ - struct bencode_str s; - inplace_ben_str(&s, key, strlen(key)); - return ben_dict_get(dict, (struct bencode *) &s); -} - -struct bencode *ben_dict_get_by_int(const struct bencode *dict, long long key) -{ - struct bencode_int i; - inplace_ben_int(&i, key); - return ben_dict_get(dict, (struct bencode *) &i); -} - -struct bencode_keyvalue *ben_dict_ordered_items(const struct bencode *b) -{ - struct bencode_keyvalue *pairs; - size_t i; - const struct bencode_dict *dict = ben_dict_const_cast(b); - if (dict == NULL) - return NULL; - pairs = malloc(dict->n * sizeof(pairs[0])); - if (pairs == NULL) - return NULL; - for (i = 0; i < dict->n; i++) { - pairs[i].key = dict->nodes[i].key; - pairs[i].value = dict->nodes[i].value; - } - qsort(pairs, dict->n, sizeof(pairs[0]), ben_cmp_qsort); - return pairs; -} - -static size_t dict_find_pos(struct bencode_dict *d, - const struct bencode *key, long long hash) -{ - size_t pos = hash_bucket_head(hash, d); - while (pos != -1) { - assert(pos < d->n); - if (d->nodes[pos].hash == hash && - ben_cmp(d->nodes[pos].key, key) == 0) - break; - pos = d->nodes[pos].next; - } - return pos; -} - -static void dict_unlink(struct bencode_dict *d, size_t bucket, size_t unlinkpos) -{ - size_t pos = d->buckets[bucket]; - size_t next; - size_t nextnext; - - assert(unlinkpos < d->n); - - if (pos == unlinkpos) { - next = d->nodes[unlinkpos].next; - assert(next < d->n || next == -1); - d->buckets[bucket] = next; - return; - } - while (pos != -1) { - assert(pos < d->n); - next = d->nodes[pos].next; - if (next == unlinkpos) { - nextnext = d->nodes[next].next; - assert(nextnext < d->n || nextnext == -1); - d->nodes[pos].next = nextnext; - return; - } - pos = next; - } - die("Key should have been found. Can not unlink position %zu.\n", unlinkpos); -} - -/* Remove node from the linked list, if found */ -static struct bencode *dict_pop(struct bencode_dict *d, - const struct bencode *key, long long hash) -{ - struct bencode *value; - size_t removebucket = hash_bucket(hash, d); - size_t tailpos = d->n - 1; - size_t tailhash = d->nodes[tailpos].hash; - size_t tailbucket = hash_bucket(tailhash, d); - size_t removepos; - - removepos = dict_find_pos(d, key, hash); - if (removepos == -1) - return NULL; - key = NULL; /* avoid using the pointer again, it may not be valid */ - - /* - * WARNING: complicated code follows. - * - * First, unlink the node to be removed and the tail node. - * We will actually later swap the positions of removed node and - * tail node inside the d->nodes array. We want to preserve - * d->nodes array in a state where positions from 0 to (d->n - 1) - * are always occupied with a valid node. This is done to make - * dictionary walk fast by simply walking positions 0 to (d->n - 1) - * in a for loop. - */ - dict_unlink(d, removebucket, removepos); - if (removepos != tailpos) - dict_unlink(d, tailbucket, tailpos); - - /* Then read the removed node and free its key */ - value = d->nodes[removepos].value; - ben_free(d->nodes[removepos].key); - - /* Then re-insert the unliked tail node in the place of removed node */ - d->nodes[removepos] = d->nodes[tailpos]; - memset(&d->nodes[tailpos], 0, sizeof d->nodes[tailpos]); /* poison */ - d->nodes[tailpos].next = ((size_t) -1) / 2; - - /* - * Then re-link the tail node to its bucket, unless the tail node - * was the one to be removed. - */ - if (removepos != tailpos) { - d->nodes[removepos].next = d->buckets[tailbucket]; - d->buckets[tailbucket] = removepos; - } - - d->n--; - - if (d->n <= (d->alloc / 4) && d->alloc >= 8) - resize_dict(d, d->alloc / 2); - - return value; -} - -struct bencode *ben_dict_pop(struct bencode *dict, const struct bencode *key) -{ - struct bencode_dict *d = ben_dict_cast(dict); - return dict_pop(d, key, ben_hash(key)); -} - -struct bencode *ben_dict_pop_by_str(struct bencode *dict, const char *key) -{ - struct bencode_str s; - inplace_ben_str(&s, key, strlen(key)); - return ben_dict_pop(dict, (struct bencode *) &s); -} - -struct bencode *ben_dict_pop_by_int(struct bencode *dict, long long key) -{ - struct bencode_int i; - inplace_ben_int(&i, key); - return ben_dict_pop(dict, (struct bencode *) &i); -} - -/* This can be used from the ben_dict_for_each() iterator */ -struct bencode *ben_dict_pop_current(struct bencode *dict, size_t *pos) -{ - struct bencode_dict *d = ben_dict_cast(dict); - struct bencode *value = ben_dict_pop(dict, d->nodes[*pos].key); - (*pos)--; - return value; -} - -int ben_dict_set(struct bencode *dict, struct bencode *key, struct bencode *value) -{ - struct bencode_dict *d = ben_dict_cast(dict); - long long hash = ben_hash(key); - size_t bucket; - size_t pos; - - assert(value != NULL); - - pos = hash_bucket_head(hash, d); - for (; pos != -1; pos = d->nodes[pos].next) { - assert(pos < d->n); - if (d->nodes[pos].hash != hash || ben_cmp(d->nodes[pos].key, key) != 0) - continue; - ben_free(d->nodes[pos].key); - ben_free(d->nodes[pos].value); - d->nodes[pos].key = key; - d->nodes[pos].value = value; - /* 'hash' and 'next' members stay the same */ - return 0; - } - - assert(d->n <= d->alloc); - if (d->n == d->alloc && resize_dict(d, -1)) - return -1; - - bucket = hash_bucket(hash, d); - pos = d->n; - d->nodes[pos] = (struct bencode_dict_node) {.hash = hash, - .key = key, - .value = value, - .next = d->buckets[bucket]}; - d->n++; - d->buckets[bucket] = pos; - return 0; -} - -int ben_dict_set_by_str(struct bencode *dict, const char *key, struct bencode *value) -{ - struct bencode *bkey = ben_str(key); - if (bkey == NULL) - return -1; - if (ben_dict_set(dict, bkey, value)) { - ben_free(bkey); - return -1; - } - return 0; -} - -int ben_dict_set_str_by_str(struct bencode *dict, const char *key, const char *value) -{ - struct bencode *bkey = ben_str(key); - struct bencode *bvalue = ben_str(value); - if (bkey == NULL || bvalue == NULL) { - ben_free(bkey); - ben_free(bvalue); - return -1; - } - if (ben_dict_set(dict, bkey, bvalue)) { - ben_free(bkey); - ben_free(bvalue); - return -1; - } - return 0; -} - -struct bencode *ben_int(long long ll) -{ - struct bencode_int *b = alloc(BENCODE_INT); - if (b == NULL) - return NULL; - b->ll = ll; - return (struct bencode *) b; -} - -struct bencode *ben_list(void) -{ - return alloc(BENCODE_LIST); -} - -int ben_list_append(struct bencode *list, struct bencode *b) -{ - struct bencode_list *l = ben_list_cast(list); - /* NULL pointer de-reference if the cast fails */ - assert(l->n <= l->alloc); - if (l->n == l->alloc && resize_list(l, -1)) - return -1; - assert(b != NULL); - l->values[l->n] = b; - l->n++; - return 0; -} - -int ben_list_append_str(struct bencode *list, const char *s) -{ - struct bencode *bs = ben_str(s); - if (bs == NULL) - return -1; - return ben_list_append(list, bs); -} - -int ben_list_append_int(struct bencode *list, long long ll) -{ - struct bencode *bll = ben_int(ll); - if (bll == NULL) - return -1; - return ben_list_append(list, bll); -} - -struct bencode *ben_list_pop(struct bencode *list, size_t pos) -{ - struct bencode_list *l = ben_list_cast(list); - struct bencode *value; - - assert(pos < l->n); - - value = ben_list_get(list, pos); - - for (; (pos + 1) < l->n; pos++) - l->values[pos] = l->values[pos + 1]; - - l->values[l->n - 1] = NULL; - l->n--; - return value; -} - -void ben_list_set(struct bencode *list, size_t i, struct bencode *b) -{ - struct bencode_list *l = ben_list_cast(list); - if (i >= l->n) - die("ben_list_set() out of bounds: %zu\n", i); - - ben_free(l->values[i]); - assert(b != NULL); - l->values[i] = b; -} - -char *ben_print(const struct bencode *b) -{ - size_t size = get_printed_size(b); - char *data = malloc(size + 1); - struct ben_encode_ctx ctx = {.data = data, .size = size, .pos = 0}; - if (data == NULL) { - //warn("No memory to print\n"); - return NULL; - } - if (print(&ctx, b)) { - free(data); - return NULL; - } - assert(ctx.pos == size); - data[ctx.pos] = 0; - return data; -} - -struct bencode *ben_str(const char *s) -{ - return ben_blob(s, strlen(s)); -} - -const char *ben_strerror(int error) -{ - switch (error) { - case BEN_OK: - return "OK (no error)"; - case BEN_INVALID: - return "Invalid data"; - case BEN_INSUFFICIENT: - return "Insufficient amount of data (need more data)"; - case BEN_NO_MEMORY: - return "Out of memory"; - case BEN_MISMATCH: - return "A given structure did not match unpack format"; - default: - fprintf(stderr, "Unknown error code: %d\n", error); - return NULL; - } -} - -static int unpack_pointer(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - const char **str; - const struct bencode **ptr; - - ctx->off++; - - if (ctx->off >= ctx->len) - return insufficient(ctx); - - switch (ben_current_char(ctx)) { - case 's': /* %ps */ - ctx->off++; - if (b->type != BENCODE_STR) - return mismatch(ctx); - str = va_arg(*vl, const char **); - *str = ben_str_val(b); - return 0; - - case 'b': /* %pb */ - ctx->off++; - ptr = va_arg(*vl, const struct bencode **); - *ptr = b; - return 0; - - default: - return invalid(ctx); - } -} - -static int unpack_value(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - long long val; - long long *ll; - long *l; - int *i; - unsigned long long *ull; - unsigned long *ul; - unsigned int *ui; - int longflag = 0; - - ctx->off++; - - while (ctx->off < ctx->len) { - switch (ben_current_char(ctx)) { - case 'l': - ctx->off++; - longflag++; - break; - case 'L': - case 'q': - ctx->off++; - longflag = 2; - break; - - case 'p': - return unpack_pointer(b, ctx, vl); - - /* signed */ - case 'd': - ctx->off++; - if (b->type != BENCODE_INT) - return mismatch(ctx); - val = ben_int_val(b); - switch (longflag) { - case 0: - i = va_arg(*vl, int *); - *i = val; - /* Test that no information was lost in conversion */ - if ((long long) *i != val) - return mismatch(ctx); - break; - case 1: - l = va_arg(*vl, long *); - *l = val; - if ((long long) *l != val) - return mismatch(ctx); - break; - case 2: - ll = va_arg(*vl, long long *); - *ll = val; - break; - } - return 0; - - /* unsigned */ - case 'u': - ctx->off++; - if (b->type != BENCODE_INT) - return mismatch(ctx); - val = ben_int_val(b); - if (val < 0) - return mismatch(ctx); - switch (longflag) { - case 0: - ui = va_arg(*vl, unsigned int *); - *ui = val; - if ((long long) *ui != val) - return mismatch(ctx); - break; - case 1: - ul = va_arg(*vl, unsigned long *); - *ul = val; - if ((long long) *ul != val) - return mismatch(ctx); - break; - case 2: - ull = va_arg(*vl, unsigned long long *); - *ull = val; - break; - } - return 0; - - default: - return invalid(ctx); - } - } - return insufficient(ctx); -} - -static int unpack_dict(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - struct bencode *key = NULL; - const struct bencode *val; - - if (b->type != BENCODE_DICT) - return mismatch(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - return -1; - - if (ben_current_char(ctx) == '}') { - ctx->off++; - break; - } - switch (ben_current_char(ctx)) { - case '\'': - case '"': - key = decode_printed_str(ctx); - break; - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - key = decode_printed_int(ctx); - break; - default: - return invalid(ctx); - } - if (key == NULL) - return -1; - val = ben_dict_get(b, key); - ben_free(key); - if (val == NULL) - return mismatch(ctx); - - if (seek_char(ctx)) - return -1; - if (ben_current_char(ctx) != ':') - return invalid(ctx); - ctx->off++; - - if (unpack(val, ctx, vl)) - return -1; - - if (seek_char(ctx)) - return -1; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != '}') - return invalid(ctx); - } - return 0; -} - -static int unpack_list(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - const struct bencode_list *list; - size_t i = 0; - - if (b->type != BENCODE_LIST) - return mismatch(ctx); - list = ben_list_const_cast(b); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - return -1; - - if (ben_current_char(ctx) == ']') { - ctx->off++; - break; - } - if (i >= list->n) - return mismatch(ctx); - if (unpack(list->values[i], ctx, vl)) - return -1; - i++; - - if (seek_char(ctx)) - return -1; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != ']') - return invalid(ctx); - } - if (i != list->n) - return mismatch(ctx); - return 0; -} - -static int unpack(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - if (seek_char(ctx)) - return insufficient(ctx); - - switch (ben_current_char(ctx)) { - case '{': - return unpack_dict(b, ctx, vl); - case '[': - return unpack_list(b, ctx, vl); - case '%': - return unpack_value(b, ctx, vl); - default: - break; - } - return -1; -} - -static int unpack_all(const struct bencode *b, struct ben_decode_ctx *ctx, - va_list *vl) -{ - if (unpack(b, ctx, vl)) - return -1; - /* check for left over characters */ - seek_char(ctx); - ctx->error = 0; - if (ctx->off < ctx->len) - return invalid(ctx); - return 0; -} - -int ben_unpack(const struct bencode *b, const char *fmt, ...) -{ - struct ben_decode_ctx ctx = {.data = fmt, .len = strlen(fmt)}; - int ret; - va_list vl; - va_start(vl, fmt); - ret = unpack_all(b, &ctx, &vl); - va_end(vl); - return ret; -} - -int ben_unpack2(const struct bencode *b, size_t *off, struct bencode_error *error, const char *fmt, ...) -{ - struct ben_decode_ctx ctx = {.data = fmt, .len = strlen(fmt)}; - int ret; - va_list vl; - va_start(vl, fmt); - ret = unpack_all(b, &ctx, &vl); - va_end(vl); - - *off = ctx.off; - if (error != NULL) { - assert((ret == 0) ^ (ctx.error != 0)); - error->error = ctx.error; - if (ret != 0) { - error->off = 0; - error->line = 0; - } else { - error->off = ctx.off; - error->line = ctx.line; - } - } - return 0; -} - -static struct bencode *pack_pointer(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *b = NULL; - - ctx->off++; - - if (ctx->off >= ctx->len) - return ben_insufficient_ptr(ctx); - - switch (ben_current_char(ctx)) { - case 'b': /* %pb */ - ctx->off++; - b = va_arg(*vl, struct bencode *); - break; - default: - return ben_invalid_ptr(ctx); - } - return b; -} - -static struct bencode *pack_value(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *b = NULL; - unsigned long long ull; - long long val; - int longflag = 0; - - ctx->off++; - - while (ctx->off < ctx->len) { - switch (ben_current_char(ctx)) { - case 'l': - ctx->off++; - longflag++; - break; - case 'L': - case 'q': - ctx->off++; - longflag = 2; - break; - - case 's': - ctx->off++; - b = ben_str(va_arg(*vl, const char *)); - if (b == NULL) - return ben_oom_ptr(ctx); - break; - - case 'p': - b = pack_pointer(ctx, vl); - break; - - /* signed */ - case 'd': - ctx->off++; - switch (longflag) { - case 0: - val = va_arg(*vl, int); - break; - case 1: - val = va_arg(*vl, long); - break; - case 2: - val = va_arg(*vl, long long); - break; - default: - return ben_invalid_ptr(ctx); - } - b = ben_int(val); - if (b == NULL) - return ben_oom_ptr(ctx); - break; - - /* unsigned */ - case 'u': - ctx->off++; - switch (longflag) { - case 0: - val = va_arg(*vl, unsigned int); - break; - case 1: - val = va_arg(*vl, unsigned long); - break; - case 2: - ull = va_arg(*vl, unsigned long long); - /* Check that no information was lost */ - val = ull; - if ((long long) ull != val) - return ben_invalid_ptr(ctx); - break; - default: - return ben_invalid_ptr(ctx); - } - b = ben_int(val); - if (b == NULL) - return ben_oom_ptr(ctx); - break; - - default: - return ben_invalid_ptr(ctx); - } - if (b) - return b; - } - return ben_insufficient_ptr(ctx); -} - -static struct bencode *pack_dict(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *d = ben_dict(); - struct bencode *key = NULL; - struct bencode *value = NULL; - - if (d == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - - if (ben_current_char(ctx) == '}') { - ctx->off++; - break; - } - key = pack(ctx, vl); - if (key == NULL) - goto nullpath; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) != ':') - goto invalidpath; - ctx->off++; - - value = pack(ctx, vl); - if (value == NULL) - goto nullpath; - - if (ben_dict_set(d, key, value)) { - ben_free(key); - ben_free(value); - ben_free(d); - return ben_oom_ptr(ctx); - } - key = NULL; - value = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != '}') - goto invalidpath; - } - return d; - -nullpath: - ben_free(d); - ben_free(key); - ben_free(value); - return NULL; - -invalidpath: - ben_free(d); - ben_free(key); - ben_free(value); - return ben_invalid_ptr(ctx); -} - -static struct bencode *pack_list(struct ben_decode_ctx *ctx, va_list *vl) -{ - struct bencode *l = ben_list(); - struct bencode *val = NULL; - - if (l == NULL) - return ben_oom_ptr(ctx); - - ctx->off++; - - while (1) { - if (seek_char(ctx)) - goto nullpath; - - if (ben_current_char(ctx) == ']') { - ctx->off++; - break; - } - val = pack(ctx, vl); - if (val == NULL) - goto nullpath; - - if (ben_list_append(l, val)) { - ben_free(val); - ben_free(l); - return ben_oom_ptr(ctx); - } - val = NULL; - - if (seek_char(ctx)) - goto nullpath; - if (ben_current_char(ctx) == ',') - ctx->off++; - else if (ben_current_char(ctx) != ']') { - ben_free(l); - return ben_invalid_ptr(ctx); - } - } - - return l; - -nullpath: - ben_free(l); - ben_free(val); - return NULL; -} - -static struct bencode *pack(struct ben_decode_ctx *ctx, va_list *vl) -{ - if (seek_char(ctx)) - return ben_insufficient_ptr(ctx); - - switch (ben_current_char(ctx)) { - case '\'': - case '"': - return decode_printed_str(ctx); - case '-': - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - return decode_printed_int(ctx); - case 'F': - case 'T': - return decode_printed_bool(ctx); - case '{': - return pack_dict(ctx, vl); - case '[': - return pack_list(ctx, vl); - case '%': - return pack_value(ctx, vl); - default: - return ben_invalid_ptr(ctx); - } - return NULL; -} - -struct bencode *ben_pack(const char *fmt, ...) -{ - struct ben_decode_ctx ctx = {.data = fmt, .len = strlen(fmt)}; - struct bencode *b; - va_list vl; - va_start(vl, fmt); - b = pack(&ctx, &vl); - va_end(vl); - - /* check for left over characters */ - seek_char(&ctx); - if (ctx.off < ctx.len) { - ben_free(b); - return NULL; - } - return b; -} diff --git a/libs/libblade/src/unqlite.c b/libs/libblade/src/unqlite.c deleted file mode 100644 index ee79ffaa00..0000000000 --- a/libs/libblade/src/unqlite.c +++ /dev/null @@ -1,60240 +0,0 @@ -#ifndef _WIN32 -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#endif - -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2016, Symisc Systems http://unqlite.org/ - * Copyright (C) 2014, Yuras Shumovich - * Version 1.1.7 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ -/* - * Copyright (C) 2012, 2016 Symisc Systems, S.U.A.R.L [M.I.A.G Mrad Chems Eddine ]. - * 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 SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SYMISC SYSTEMS - * 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. - */ -/* - * $SymiscID: unqlite.c v1.1.7 Win10 2106-12-02 00:04:12 stable $ - */ -/* This file is an amalgamation of many separate C source files from unqlite version 1.1.6 - * 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 optimization's - * that would not be possible if the files were compiled separately. Performance improvements - * are commonly seen when unqlite is compiled as a single translation unit. - * - * This file is all you need to compile unqlite. To use unqlite in other programs, you need - * this file and the "unqlite.h" header file that defines the programming interface to the - * unqlite engine.(If you do not have the "unqlite.h" header file at hand, you will find - * a copy embedded within the text of this file.Search for "Header file: " to find - * the start of the embedded unqlite.h header file.) Additional code files may be needed if - * you want a wrapper to interface unqlite with your choice of programming language. - * To get the official documentation, please visit http://unqlite.org/ - */ - /* - * Make the sure the following directive is defined in the amalgamation build. - */ - #ifndef UNQLITE_AMALGAMATION - #define UNQLITE_AMALGAMATION - #define JX9_AMALGAMATION - /* Marker for routines not intended for external use */ - #define JX9_PRIVATE static - #endif /* UNQLITE_AMALGAMATION */ -/* - * Embedded header file for unqlite: - */ -/* - * ---------------------------------------------------------- - * File: unqlite.h - * MD5: d26e9847c6587edbbb183d0115d172cb - * ---------------------------------------------------------- - */ -/* This file was automatically generated. Do not edit (Except for compile time directives)! */ -#ifndef _UNQLITE_H_ -#define _UNQLITE_H_ -/* - * Symisc UnQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2016, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ -/* - * Copyright (C) 2012, 2016 Symisc Systems, S.U.A.R.L [M.I.A.G Mrad Chems Eddine ]. - * 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 SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SYMISC SYSTEMS - * 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. - */ - /* $SymiscID: unqlite.h v1.2 Win10 2106-12-02 00:04:12 stable $ */ -#include /* needed for the definition of va_list */ -/* - * Compile time engine version, signature, identification in the symisc source tree - * and copyright notice. - * Each macro have an equivalent C interface associated with it that provide the same - * information but are associated with the library instead of the header file. - * Refer to [unqlite_lib_version()], [unqlite_lib_signature()], [unqlite_lib_ident()] and - * [unqlite_lib_copyright()] for more information. - */ -/* - * The UNQLITE_VERSION C preprocessor macroevaluates to a string literal - * that is the unqlite version in the format "X.Y.Z" where X is the major - * version number and Y is the minor version number and Z is the release - * number. - */ -#define UNQLITE_VERSION "1.1.7" -/* - * The UNQLITE_VERSION_NUMBER C preprocessor macro resolves to an integer - * with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same - * numbers used in [UNQLITE_VERSION]. - */ -#define UNQLITE_VERSION_NUMBER 1001007 -/* - * The UNQLITE_SIG C preprocessor macro evaluates to a string - * literal which is the public signature of the unqlite engine. - * This signature could be included for example in a host-application - * generated Server MIME header as follows: - * Server: YourWebServer/x.x unqlite/x.x.x \r\n - */ -#define UNQLITE_SIG "unqlite/1.1.7" -/* - * UnQLite identification in the Symisc source tree: - * Each particular check-in of a particular software released - * by symisc systems have an unique identifier associated with it. - * This macro hold the one associated with unqlite. - */ -#define UNQLITE_IDENT "unqlite:b172a1e2c3f62fb35c8e1fb2795121f82356cad6" -/* - * Copyright notice. - * If you have any questions about the licensing situation, please - * visit http://unqlite.org/licensing.html - * or contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - */ -#define UNQLITE_COPYRIGHT "Copyright (C) Symisc Systems, S.U.A.R.L [Mrad Chems Eddine ] 2012-2016, http://unqlite.org/" -/* Make sure we can call this stuff from C++ */ -#ifdef __cplusplus -extern "C" { -#endif -/* Forward declaration to public objects */ -typedef struct unqlite_io_methods unqlite_io_methods; -typedef struct unqlite_kv_methods unqlite_kv_methods; -typedef struct unqlite_kv_engine unqlite_kv_engine; -typedef struct jx9_io_stream unqlite_io_stream; -typedef struct jx9_context unqlite_context; -typedef struct jx9_value unqlite_value; -typedef struct unqlite_vfs unqlite_vfs; -typedef struct unqlite_vm unqlite_vm; -typedef struct unqlite unqlite; -/* - * ------------------------------ - * Compile time directives - * ------------------------------ - * For most purposes, UnQLite can be built just fine using the default compilation options. - * However, if required, the compile-time options documented below can be used to omit UnQLite - * features (resulting in a smaller compiled library size) or to change the default values - * of some parameters. - * Every effort has been made to ensure that the various combinations of compilation options - * work harmoniously and produce a working library. - * - * UNQLITE_ENABLE_THREADS - * This option controls whether or not code is included in UnQLite to enable it to operate - * safely in a multithreaded environment. The default is not. All mutexing code is omitted - * and it is unsafe to use UnQLite in a multithreaded program. When compiled with the - * UNQLITE_ENABLE_THREADS directive enabled, UnQLite can be used in a multithreaded program - * and it is safe to share the same virtual machine and engine handle between two or more threads. - * The value of UNQLITE_ENABLE_THREADS can be determined at run-time using the unqlite_lib_is_threadsafe() - * interface. - * When UnQLite has been compiled with threading support then the threading mode can be altered - * at run-time using the unqlite_lib_config() interface together with one of these verbs: - * UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE - * UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI - * Platforms others than Windows and UNIX systems must install their own mutex subsystem via - * unqlite_lib_config() with a configuration verb set to UNQLITE_LIB_CONFIG_USER_MUTEX. - * Otherwise the library is not threadsafe. - * Note that you must link UnQLite with the POSIX threads library under UNIX systems (i.e: -lpthread). - * - * Options To Omit/Enable Features - * - * The following options can be used to reduce the size of the compiled library by omitting optional - * features. This is probably only useful in embedded systems where space is especially tight, as even - * with all features included the UnQLite library is relatively small. Don't forget to tell your - * compiler to optimize for binary size! (the -Os option if using GCC). Telling your compiler - * to optimize for size usually has a much larger impact on library footprint than employing - * any of these compile-time options. - * - * JX9_DISABLE_BUILTIN_FUNC - * Jx9 is shipped with more than 312 built-in functions suitable for most purposes like - * string and INI processing, ZIP extracting, Base64 encoding/decoding, JSON encoding/decoding - * and so forth. - * If this directive is enabled, then all built-in Jx9 functions are omitted from the build. - * Note that special functions such as db_create(), db_store(), db_fetch(), etc. are not omitted - * from the build and are not affected by this directive. - * - * JX9_ENABLE_MATH_FUNC - * If this directive is enabled, built-in math functions such as sqrt(), abs(), log(), ceil(), etc. - * are included in the build. Note that you may need to link UnQLite with the math library in same - * Linux/BSD flavor (i.e: -lm). - * - * JX9_DISABLE_DISK_IO - * If this directive is enabled, built-in VFS functions such as chdir(), mkdir(), chroot(), unlink(), - * sleep(), etc. are omitted from the build. - * - * UNQLITE_ENABLE_JX9_HASH_IO - * If this directive is enabled, built-in hash functions such as md5(), sha1(), md5_file(), crc32(), etc. - * are included in the build. - */ -/* Symisc public definitions */ -#if !defined(SYMISC_STANDARD_DEFS) -#define SYMISC_STANDARD_DEFS -#if defined (_WIN32) || defined (WIN32) || defined(__MINGW32__) || defined (_MSC_VER) || defined (_WIN32_WCE) -/* Windows Systems */ -#if !defined(__WINNT__) -#define __WINNT__ -#endif -/* - * Determine if we are dealing with WindowsCE - which has a much - * reduced API. - */ -#if defined(_WIN32_WCE) -#ifndef __WIN_CE__ -#define __WIN_CE__ -#endif /* __WIN_CE__ */ -#endif /* _WIN32_WCE */ -#else -/* - * By default we will assume that we are compiling on a UNIX systems. - * Otherwise the OS_OTHER directive must be defined. - */ -#if !defined(OS_OTHER) -#if !defined(__UNIXES__) -#define __UNIXES__ -#endif /* __UNIXES__ */ -#else -#endif /* OS_OTHER */ -#endif /* __WINNT__/__UNIXES__ */ -#if defined(_MSC_VER) || defined(__BORLANDC__) -typedef signed __int64 sxi64; /* 64 bits(8 bytes) signed int64 */ -typedef unsigned __int64 sxu64; /* 64 bits(8 bytes) unsigned int64 */ -#else -typedef signed long long int sxi64; /* 64 bits(8 bytes) signed int64 */ -typedef unsigned long long int sxu64; /* 64 bits(8 bytes) unsigned int64 */ -#endif /* _MSC_VER */ -/* Signature of the consumer routine */ -typedef int (*ProcConsumer)(const void *, unsigned int, void *); -/* Forward reference */ -typedef struct SyMutexMethods SyMutexMethods; -typedef struct SyMemMethods SyMemMethods; -typedef struct SyString SyString; -typedef struct syiovec syiovec; -typedef struct SyMutex SyMutex; -typedef struct Sytm Sytm; -/* Scatter and gather array. */ -struct syiovec -{ -#if defined (__WINNT__) - /* Same fields type and offset as WSABUF structure defined one winsock2 header */ - unsigned long nLen; - char *pBase; -#else - void *pBase; - unsigned long nLen; -#endif -}; -struct SyString -{ - const char *zString; /* Raw string (may not be null terminated) */ - unsigned int nByte; /* Raw string length */ -}; -/* Time structure. */ -struct Sytm -{ - int tm_sec; /* seconds (0 - 60) */ - int tm_min; /* minutes (0 - 59) */ - int tm_hour; /* hours (0 - 23) */ - int tm_mday; /* day of month (1 - 31) */ - int tm_mon; /* month of year (0 - 11) */ - int tm_year; /* year + 1900 */ - int tm_wday; /* day of week (Sunday = 0) */ - int tm_yday; /* day of year (0 - 365) */ - int tm_isdst; /* is summer time in effect? */ - char *tm_zone; /* abbreviation of timezone name */ - long tm_gmtoff; /* offset from UTC in seconds */ -}; -/* Convert a tm structure (struct tm *) found in to a Sytm structure */ -#define STRUCT_TM_TO_SYTM(pTM, pSYTM) \ - (pSYTM)->tm_hour = (pTM)->tm_hour;\ - (pSYTM)->tm_min = (pTM)->tm_min;\ - (pSYTM)->tm_sec = (pTM)->tm_sec;\ - (pSYTM)->tm_mon = (pTM)->tm_mon;\ - (pSYTM)->tm_mday = (pTM)->tm_mday;\ - (pSYTM)->tm_year = (pTM)->tm_year + 1900;\ - (pSYTM)->tm_yday = (pTM)->tm_yday;\ - (pSYTM)->tm_wday = (pTM)->tm_wday;\ - (pSYTM)->tm_isdst = (pTM)->tm_isdst;\ - (pSYTM)->tm_gmtoff = 0;\ - (pSYTM)->tm_zone = 0; - -/* Convert a SYSTEMTIME structure (LPSYSTEMTIME: Windows Systems only ) to a Sytm structure */ -#define SYSTEMTIME_TO_SYTM(pSYSTIME, pSYTM) \ - (pSYTM)->tm_hour = (pSYSTIME)->wHour;\ - (pSYTM)->tm_min = (pSYSTIME)->wMinute;\ - (pSYTM)->tm_sec = (pSYSTIME)->wSecond;\ - (pSYTM)->tm_mon = (pSYSTIME)->wMonth - 1;\ - (pSYTM)->tm_mday = (pSYSTIME)->wDay;\ - (pSYTM)->tm_year = (pSYSTIME)->wYear;\ - (pSYTM)->tm_yday = 0;\ - (pSYTM)->tm_wday = (pSYSTIME)->wDayOfWeek;\ - (pSYTM)->tm_gmtoff = 0;\ - (pSYTM)->tm_isdst = -1;\ - (pSYTM)->tm_zone = 0; - -/* Dynamic memory allocation methods. */ -struct SyMemMethods -{ - void * (*xAlloc)(unsigned int); /* [Required:] Allocate a memory chunk */ - void * (*xRealloc)(void *, unsigned int); /* [Required:] Re-allocate a memory chunk */ - void (*xFree)(void *); /* [Required:] Release a memory chunk */ - unsigned int (*xChunkSize)(void *); /* [Optional:] Return chunk size */ - int (*xInit)(void *); /* [Optional:] Initialization callback */ - void (*xRelease)(void *); /* [Optional:] Release callback */ - void *pUserData; /* [Optional:] First argument to xInit() and xRelease() */ -}; -/* Out of memory callback signature. */ -typedef int (*ProcMemError)(void *); -/* Mutex methods. */ -struct SyMutexMethods -{ - int (*xGlobalInit)(void); /* [Optional:] Global mutex initialization */ - void (*xGlobalRelease)(void); /* [Optional:] Global Release callback () */ - SyMutex * (*xNew)(int); /* [Required:] Request a new mutex */ - void (*xRelease)(SyMutex *); /* [Optional:] Release a mutex */ - void (*xEnter)(SyMutex *); /* [Required:] Enter mutex */ - int (*xTryEnter)(SyMutex *); /* [Optional:] Try to enter a mutex */ - void (*xLeave)(SyMutex *); /* [Required:] Leave a locked mutex */ -}; -#if defined (_MSC_VER) || defined (__MINGW32__) || defined (__GNUC__) && defined (__declspec) -#define SX_APIIMPORT __declspec(dllimport) -#define SX_APIEXPORT __declspec(dllexport) -#else -#define SX_APIIMPORT -#define SX_APIEXPORT -#endif -/* Standard return values from Symisc public interfaces */ -#define SXRET_OK 0 /* Not an error */ -#define SXERR_MEM (-1) /* Out of memory */ -#define SXERR_IO (-2) /* IO error */ -#define SXERR_EMPTY (-3) /* Empty field */ -#define SXERR_LOCKED (-4) /* Locked operation */ -#define SXERR_ORANGE (-5) /* Out of range value */ -#define SXERR_NOTFOUND (-6) /* Item not found */ -#define SXERR_LIMIT (-7) /* Limit reached */ -#define SXERR_MORE (-8) /* Need more input */ -#define SXERR_INVALID (-9) /* Invalid parameter */ -#define SXERR_ABORT (-10) /* User callback request an operation abort */ -#define SXERR_EXISTS (-11) /* Item exists */ -#define SXERR_SYNTAX (-12) /* Syntax error */ -#define SXERR_UNKNOWN (-13) /* Unknown error */ -#define SXERR_BUSY (-14) /* Busy operation */ -#define SXERR_OVERFLOW (-15) /* Stack or buffer overflow */ -#define SXERR_WILLBLOCK (-16) /* Operation will block */ -#define SXERR_NOTIMPLEMENTED (-17) /* Operation not implemented */ -#define SXERR_EOF (-18) /* End of input */ -#define SXERR_PERM (-19) /* Permission error */ -#define SXERR_NOOP (-20) /* No-op */ -#define SXERR_FORMAT (-21) /* Invalid format */ -#define SXERR_NEXT (-22) /* Not an error */ -#define SXERR_OS (-23) /* System call return an error */ -#define SXERR_CORRUPT (-24) /* Corrupted pointer */ -#define SXERR_CONTINUE (-25) /* Not an error: Operation in progress */ -#define SXERR_NOMATCH (-26) /* No match */ -#define SXERR_RESET (-27) /* Operation reset */ -#define SXERR_DONE (-28) /* Not an error */ -#define SXERR_SHORT (-29) /* Buffer too short */ -#define SXERR_PATH (-30) /* Path error */ -#define SXERR_TIMEOUT (-31) /* Timeout */ -#define SXERR_BIG (-32) /* Too big for processing */ -#define SXERR_RETRY (-33) /* Retry your call */ -#define SXERR_IGNORE (-63) /* Ignore */ -#endif /* SYMISC_PUBLIC_DEFS */ -/* - * Marker for exported interfaces. - */ -#define UNQLITE_APIEXPORT SX_APIEXPORT -/* - * If compiling for a processor that lacks floating point - * support, substitute integer for floating-point. - */ -#ifdef UNQLITE_OMIT_FLOATING_POINT -typedef sxi64 uqlite_real; -#else -typedef double unqlite_real; -#endif -typedef sxi64 unqlite_int64; -/* Standard UnQLite return values */ -#define UNQLITE_OK SXRET_OK /* Successful result */ -/* Beginning of error codes */ -#define UNQLITE_NOMEM SXERR_MEM /* Out of memory */ -#define UNQLITE_ABORT SXERR_ABORT /* Another thread have released this instance */ -#define UNQLITE_IOERR SXERR_IO /* IO error */ -#define UNQLITE_CORRUPT SXERR_CORRUPT /* Corrupt pointer */ -#define UNQLITE_LOCKED SXERR_LOCKED /* Forbidden Operation */ -#define UNQLITE_BUSY SXERR_BUSY /* The database file is locked */ -#define UNQLITE_DONE SXERR_DONE /* Operation done */ -#define UNQLITE_PERM SXERR_PERM /* Permission error */ -#define UNQLITE_NOTIMPLEMENTED SXERR_NOTIMPLEMENTED /* Method not implemented by the underlying Key/Value storage engine */ -#define UNQLITE_NOTFOUND SXERR_NOTFOUND /* No such record */ -#define UNQLITE_NOOP SXERR_NOOP /* No such method */ -#define UNQLITE_INVALID SXERR_INVALID /* Invalid parameter */ -#define UNQLITE_EOF SXERR_EOF /* End Of Input */ -#define UNQLITE_UNKNOWN SXERR_UNKNOWN /* Unknown configuration option */ -#define UNQLITE_LIMIT SXERR_LIMIT /* Database limit reached */ -#define UNQLITE_EXISTS SXERR_EXISTS /* Record exists */ -#define UNQLITE_EMPTY SXERR_EMPTY /* Empty record */ -#define UNQLITE_COMPILE_ERR (-70) /* Compilation error */ -#define UNQLITE_VM_ERR (-71) /* Virtual machine error */ -#define UNQLITE_FULL (-73) /* Full database (unlikely) */ -#define UNQLITE_CANTOPEN (-74) /* Unable to open the database file */ -#define UNQLITE_READ_ONLY (-75) /* Read only Key/Value storage engine */ -#define UNQLITE_LOCKERR (-76) /* Locking protocol error */ -/* end-of-error-codes */ -/* - * Database Handle Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure an UnQLite database handle. - * These constants must be passed as the second argument to [unqlite_config()]. - * - * Each options require a variable number of arguments. - * The [unqlite_config()] interface will return UNQLITE_OK on success, any other - * return value indicates failure. - * For a full discussion on the configuration verbs and their expected - * parameters, please refer to this page: - * http://unqlite.org/c_api/unqlite_config.html - */ -#define UNQLITE_CONFIG_JX9_ERR_LOG 1 /* TWO ARGUMENTS: const char **pzBuf, int *pLen */ -#define UNQLITE_CONFIG_MAX_PAGE_CACHE 2 /* ONE ARGUMENT: int nMaxPage */ -#define UNQLITE_CONFIG_ERR_LOG 3 /* TWO ARGUMENTS: const char **pzBuf, int *pLen */ -#define UNQLITE_CONFIG_KV_ENGINE 4 /* ONE ARGUMENT: const char *zKvName */ -#define UNQLITE_CONFIG_DISABLE_AUTO_COMMIT 5 /* NO ARGUMENTS */ -#define UNQLITE_CONFIG_GET_KV_NAME 6 /* ONE ARGUMENT: const char **pzPtr */ -/* - * UnQLite/Jx9 Virtual Machine Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the Jx9 (Via UnQLite) Virtual machine. - * These constants must be passed as the second argument to the [unqlite_vm_config()] - * interface. - * Each options require a variable number of arguments. - * The [unqlite_vm_config()] interface will return UNQLITE_OK on success, any other return - * value indicates failure. - * There are many options but the most importants are: UNQLITE_VM_CONFIG_OUTPUT which install - * a VM output consumer callback, UNQLITE_VM_CONFIG_HTTP_REQUEST which parse and register - * a HTTP request and UNQLITE_VM_CONFIG_ARGV_ENTRY which populate the $argv array. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://unqlite.org/c_api/unqlite_vm_config.html - */ -#define UNQLITE_VM_CONFIG_OUTPUT 1 /* TWO ARGUMENTS: int (*xConsumer)(const void *pOut, unsigned int nLen, void *pUserData), void *pUserData */ -#define UNQLITE_VM_CONFIG_IMPORT_PATH 2 /* ONE ARGUMENT: const char *zIncludePath */ -#define UNQLITE_VM_CONFIG_ERR_REPORT 3 /* NO ARGUMENTS: Report all run-time errors in the VM output */ -#define UNQLITE_VM_CONFIG_RECURSION_DEPTH 4 /* ONE ARGUMENT: int nMaxDepth */ -#define UNQLITE_VM_OUTPUT_LENGTH 5 /* ONE ARGUMENT: unsigned int *pLength */ -#define UNQLITE_VM_CONFIG_CREATE_VAR 6 /* TWO ARGUMENTS: const char *zName, unqlite_value *pValue */ -#define UNQLITE_VM_CONFIG_HTTP_REQUEST 7 /* TWO ARGUMENTS: const char *zRawRequest, int nRequestLength */ -#define UNQLITE_VM_CONFIG_SERVER_ATTR 8 /* THREE ARGUMENTS: const char *zKey, const char *zValue, int nLen */ -#define UNQLITE_VM_CONFIG_ENV_ATTR 9 /* THREE ARGUMENTS: const char *zKey, const char *zValue, int nLen */ -#define UNQLITE_VM_CONFIG_EXEC_VALUE 10 /* ONE ARGUMENT: unqlite_value **ppValue */ -#define UNQLITE_VM_CONFIG_IO_STREAM 11 /* ONE ARGUMENT: const unqlite_io_stream *pStream */ -#define UNQLITE_VM_CONFIG_ARGV_ENTRY 12 /* ONE ARGUMENT: const char *zValue */ -#define UNQLITE_VM_CONFIG_EXTRACT_OUTPUT 13 /* TWO ARGUMENTS: const void **ppOut, unsigned int *pOutputLen */ -/* - * Storage engine configuration commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the underlying storage engine (i.e Hash, B+tree, R+tree). - * These constants must be passed as the first argument to [unqlite_kv_config()]. - * Each options require a variable number of arguments. - * The [unqlite_kv_config()] interface will return UNQLITE_OK on success, any other return - * value indicates failure. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://unqlite.org/c_api/unqlite_kv_config.html - */ -#define UNQLITE_KV_CONFIG_HASH_FUNC 1 /* ONE ARGUMENT: unsigned int (*xHash)(const void *,unsigned int) */ -#define UNQLITE_KV_CONFIG_CMP_FUNC 2 /* ONE ARGUMENT: int (*xCmp)(const void *,const void *,unsigned int) */ -/* - * Global Library Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the whole library. - * These constants must be passed as the first argument to [unqlite_lib_config()]. - * - * Each options require a variable number of arguments. - * The [unqlite_lib_config()] interface will return UNQLITE_OK on success, any other return - * value indicates failure. - * Notes: - * The default configuration is recommended for most applications and so the call to - * [unqlite_lib_config()] is usually not necessary. It is provided to support rare - * applications with unusual needs. - * The [unqlite_lib_config()] interface is not threadsafe. The application must insure that - * no other [unqlite_*()] interfaces are invoked by other threads while [unqlite_lib_config()] - * is running. Furthermore, [unqlite_lib_config()] may only be invoked prior to library - * initialization using [unqlite_lib_init()] or [unqlite_init()] or after shutdown - * by [unqlite_lib_shutdown()]. If [unqlite_lib_config()] is called after [unqlite_lib_init()] - * or [unqlite_init()] and before [unqlite_lib_shutdown()] then it will return UNQLITE_LOCKED. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://unqlite.org/c_api/unqlite_lib.html - */ -#define UNQLITE_LIB_CONFIG_USER_MALLOC 1 /* ONE ARGUMENT: const SyMemMethods *pMemMethods */ -#define UNQLITE_LIB_CONFIG_MEM_ERR_CALLBACK 2 /* TWO ARGUMENTS: int (*xMemError)(void *), void *pUserData */ -#define UNQLITE_LIB_CONFIG_USER_MUTEX 3 /* ONE ARGUMENT: const SyMutexMethods *pMutexMethods */ -#define UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE 4 /* NO ARGUMENTS */ -#define UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI 5 /* NO ARGUMENTS */ -#define UNQLITE_LIB_CONFIG_VFS 6 /* ONE ARGUMENT: const unqlite_vfs *pVfs */ -#define UNQLITE_LIB_CONFIG_STORAGE_ENGINE 7 /* ONE ARGUMENT: unqlite_kv_methods *pStorage */ -#define UNQLITE_LIB_CONFIG_PAGE_SIZE 8 /* ONE ARGUMENT: int iPageSize */ -/* - * These bit values are intended for use in the 3rd parameter to the [unqlite_open()] interface - * and in the 4th parameter to the xOpen method of the [unqlite_vfs] object. - */ -#define UNQLITE_OPEN_READONLY 0x00000001 /* Read only mode. Ok for [unqlite_open] */ -#define UNQLITE_OPEN_READWRITE 0x00000002 /* Ok for [unqlite_open] */ -#define UNQLITE_OPEN_CREATE 0x00000004 /* Ok for [unqlite_open] */ -#define UNQLITE_OPEN_EXCLUSIVE 0x00000008 /* VFS only */ -#define UNQLITE_OPEN_TEMP_DB 0x00000010 /* VFS only */ -#define UNQLITE_OPEN_NOMUTEX 0x00000020 /* Ok for [unqlite_open] */ -#define UNQLITE_OPEN_OMIT_JOURNALING 0x00000040 /* Omit journaling for this database. Ok for [unqlite_open] */ -#define UNQLITE_OPEN_IN_MEMORY 0x00000080 /* An in memory database. Ok for [unqlite_open]*/ -#define UNQLITE_OPEN_MMAP 0x00000100 /* Obtain a memory view of the whole file. Ok for [unqlite_open] */ -/* - * Synchronization Type Flags - * - * When UnQLite invokes the xSync() method of an [unqlite_io_methods] object it uses - * a combination of these integer values as the second argument. - * - * When the UNQLITE_SYNC_DATAONLY flag is used, it means that the sync operation only - * needs to flush data to mass storage. Inode information need not be flushed. - * If the lower four bits of the flag equal UNQLITE_SYNC_NORMAL, that means to use normal - * fsync() semantics. If the lower four bits equal UNQLITE_SYNC_FULL, that means to use - * Mac OS X style fullsync instead of fsync(). - */ -#define UNQLITE_SYNC_NORMAL 0x00002 -#define UNQLITE_SYNC_FULL 0x00003 -#define UNQLITE_SYNC_DATAONLY 0x00010 -/* - * File Locking Levels - * - * UnQLite uses one of these integer values as the second - * argument to calls it makes to the xLock() and xUnlock() methods - * of an [unqlite_io_methods] object. - */ -#define UNQLITE_LOCK_NONE 0 -#define UNQLITE_LOCK_SHARED 1 -#define UNQLITE_LOCK_RESERVED 2 -#define UNQLITE_LOCK_PENDING 3 -#define UNQLITE_LOCK_EXCLUSIVE 4 -/* - * CAPIREF: OS Interface: Open File Handle - * - * An [unqlite_file] object represents an open file in the [unqlite_vfs] OS interface - * layer. - * Individual OS interface implementations will want to subclass this object by appending - * additional fields for their own use. The pMethods entry is a pointer to an - * [unqlite_io_methods] object that defines methods for performing - * I/O operations on the open file. -*/ -typedef struct unqlite_file unqlite_file; -struct unqlite_file { - const unqlite_io_methods *pMethods; /* Methods for an open file. MUST BE FIRST */ -}; -/* - * CAPIREF: OS Interface: File Methods Object - * - * Every file opened by the [unqlite_vfs] xOpen method populates an - * [unqlite_file] object (or, more commonly, a subclass of the - * [unqlite_file] object) with a pointer to an instance of this object. - * This object defines the methods used to perform various operations - * against the open file represented by the [unqlite_file] object. - * - * If the xOpen method sets the unqlite_file.pMethods element - * to a non-NULL pointer, then the unqlite_io_methods.xClose method - * may be invoked even if the xOpen reported that it failed. The - * only way to prevent a call to xClose following a failed xOpen - * is for the xOpen to set the unqlite_file.pMethods element to NULL. - * - * The flags argument to xSync may be one of [UNQLITE_SYNC_NORMAL] or - * [UNQLITE_SYNC_FULL]. The first choice is the normal fsync(). - * The second choice is a Mac OS X style fullsync. The [UNQLITE_SYNC_DATAONLY] - * flag may be ORed in to indicate that only the data of the file - * and not its inode needs to be synced. - * - * The integer values to xLock() and xUnlock() are one of - * - * UNQLITE_LOCK_NONE - * UNQLITE_LOCK_SHARED - * UNQLITE_LOCK_RESERVED - * UNQLITE_LOCK_PENDING - * UNQLITE_LOCK_EXCLUSIVE - * - * xLock() increases the lock. xUnlock() decreases the lock. - * 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. - * - * The xSectorSize() method returns the sector size of the device that underlies - * the file. The sector size is the minimum write that can be performed without - * disturbing other bytes in the file. - * - */ -struct unqlite_io_methods { - int iVersion; /* Structure version number (currently 1) */ - int (*xClose)(unqlite_file*); - int (*xRead)(unqlite_file*, void*, unqlite_int64 iAmt, unqlite_int64 iOfst); - int (*xWrite)(unqlite_file*, const void*, unqlite_int64 iAmt, unqlite_int64 iOfst); - int (*xTruncate)(unqlite_file*, unqlite_int64 size); - int (*xSync)(unqlite_file*, int flags); - int (*xFileSize)(unqlite_file*, unqlite_int64 *pSize); - int (*xLock)(unqlite_file*, int); - int (*xUnlock)(unqlite_file*, int); - int (*xCheckReservedLock)(unqlite_file*, int *pResOut); - int (*xSectorSize)(unqlite_file*); -}; -/* - * CAPIREF: OS Interface Object - * - * An instance of the unqlite_vfs object defines the interface between - * the UnQLite core and the underlying operating system. The "vfs" - * in the name of the object stands for "Virtual File System". - * - * Only a single vfs can be registered within the UnQLite core. - * Vfs registration is done using the [unqlite_lib_config()] interface - * with a configuration verb set to UNQLITE_LIB_CONFIG_VFS. - * Note that Windows and UNIX (Linux, FreeBSD, Solaris, Mac OS X, etc.) users - * does not have to worry about registering and installing a vfs since UnQLite - * come with a built-in vfs for these platforms that implements most the methods - * defined below. - * - * Clients running on exotic systems (ie: Other than Windows and UNIX systems) - * must register their own vfs in order to be able to use the UnQLite library. - * - * The value of the iVersion field is initially 1 but may be larger in - * future versions of UnQLite. - * - * The szOsFile field is the size of the subclassed [unqlite_file] structure - * used by this VFS. mxPathname is the maximum length of a pathname in this VFS. - * - * At least szOsFile bytes of memory are allocated by UnQLite to hold the [unqlite_file] - * structure passed as the third argument to xOpen. The xOpen method does not have to - * allocate the structure; it should just fill it in. Note that the xOpen method must - * set the unqlite_file.pMethods to either a valid [unqlite_io_methods] object or to NULL. - * xOpen must do this even if the open fails. UnQLite expects that the unqlite_file.pMethods - * element will be valid after xOpen returns regardless of the success or failure of the - * xOpen call. - * - */ -struct unqlite_vfs { - const char *zName; /* Name of this virtual file system [i.e: Windows, UNIX, etc.] */ - int iVersion; /* Structure version number (currently 1) */ - int szOsFile; /* Size of subclassed unqlite_file */ - int mxPathname; /* Maximum file pathname length */ - int (*xOpen)(unqlite_vfs*, const char *zName, unqlite_file*,unsigned int flags); - int (*xDelete)(unqlite_vfs*, const char *zName, int syncDir); - int (*xAccess)(unqlite_vfs*, const char *zName, int flags, int *pResOut); - int (*xFullPathname)(unqlite_vfs*, const char *zName,int buf_len,char *zBuf); - int (*xTmpDir)(unqlite_vfs*,char *zBuf,int buf_len); - int (*xSleep)(unqlite_vfs*, int microseconds); - int (*xCurrentTime)(unqlite_vfs*,Sytm *pOut); - int (*xGetLastError)(unqlite_vfs*, int, char *); -}; -/* - * Flags for the xAccess VFS method - * - * These integer constants can be used as the third parameter to - * the xAccess method of an [unqlite_vfs] object. They determine - * what kind of permissions the xAccess method is looking for. - * With UNQLITE_ACCESS_EXISTS, the xAccess method - * simply checks whether the file exists. - * With UNQLITE_ACCESS_READWRITE, the xAccess method - * checks whether the named directory is both readable and writable - * (in other words, if files can be added, removed, and renamed within - * the directory). - * The UNQLITE_ACCESS_READWRITE constant is currently used only by the - * [temp_store_directory pragma], though this could change in a future - * release of UnQLite. - * With UNQLITE_ACCESS_READ, the xAccess method - * checks whether the file is readable. The UNQLITE_ACCESS_READ constant is - * currently unused, though it might be used in a future release of - * UnQLite. - */ -#define UNQLITE_ACCESS_EXISTS 0 -#define UNQLITE_ACCESS_READWRITE 1 -#define UNQLITE_ACCESS_READ 2 -/* - * The type used to represent a page number. The first page in a file - * is called page 1. 0 is used to represent "not a page". - * A page number is an unsigned 64-bit integer. - */ -typedef sxu64 pgno; -/* - * A database disk page is represented by an instance - * of the follwoing structure. - */ -typedef struct unqlite_page unqlite_page; -struct unqlite_page -{ - unsigned char *zData; /* Content of this page */ - void *pUserData; /* Extra content */ - pgno pgno; /* Page number for this page */ -}; -/* - * UnQLite handle to the underlying Key/Value Storage Engine (See below). - */ -typedef void * unqlite_kv_handle; -/* - * UnQLite pager IO methods. - * - * An instance of the following structure define the exported methods of the UnQLite pager - * to the underlying Key/Value storage engine. - */ -typedef struct unqlite_kv_io unqlite_kv_io; -struct unqlite_kv_io -{ - unqlite_kv_handle pHandle; /* UnQLite handle passed as the first parameter to the - * method defined below. - */ - unqlite_kv_methods *pMethods; /* Underlying storage engine */ - /* Pager methods */ - int (*xGet)(unqlite_kv_handle,pgno,unqlite_page **); - int (*xLookup)(unqlite_kv_handle,pgno,unqlite_page **); - int (*xNew)(unqlite_kv_handle,unqlite_page **); - int (*xWrite)(unqlite_page *); - int (*xDontWrite)(unqlite_page *); - int (*xDontJournal)(unqlite_page *); - int (*xDontMkHot)(unqlite_page *); - int (*xPageRef)(unqlite_page *); - int (*xPageUnref)(unqlite_page *); - int (*xPageSize)(unqlite_kv_handle); - int (*xReadOnly)(unqlite_kv_handle); - unsigned char * (*xTmpPage)(unqlite_kv_handle); - void (*xSetUnpin)(unqlite_kv_handle,void (*xPageUnpin)(void *)); - void (*xSetReload)(unqlite_kv_handle,void (*xPageReload)(void *)); - void (*xErr)(unqlite_kv_handle,const char *); -}; -/* - * Key/Value Storage Engine Cursor Object - * - * An instance of a subclass of the following object defines a cursor - * used to scan through a key-value storage engine. - */ -typedef struct unqlite_kv_cursor unqlite_kv_cursor; -struct unqlite_kv_cursor -{ - unqlite_kv_engine *pStore; /* Must be first */ - /* Subclasses will typically add additional fields */ -}; -/* - * Possible seek positions. - */ -#define UNQLITE_CURSOR_MATCH_EXACT 1 -#define UNQLITE_CURSOR_MATCH_LE 2 -#define UNQLITE_CURSOR_MATCH_GE 3 -/* - * Key/Value Storage Engine. - * - * A Key-Value storage engine is defined by an instance of the following - * object. - * UnQLite works with run-time interchangeable storage engines (i.e. Hash, B+Tree, R+Tree, LSM, etc.). - * The storage engine works with key/value pairs where both the key - * and the value are byte arrays of arbitrary length and with no restrictions on content. - * UnQLite come with two built-in KV storage engine: A Virtual Linear Hash (VLH) storage - * engine is used for persistent on-disk databases with O(1) lookup time and an in-memory - * hash-table or Red-black tree storage engine is used for in-memory databases. - * Future versions of UnQLite might add other built-in storage engines (i.e. LSM). - * Registration of a Key/Value storage engine at run-time is done via [unqlite_lib_config()] - * with a configuration verb set to UNQLITE_LIB_CONFIG_STORAGE_ENGINE. - */ -struct unqlite_kv_engine -{ - const unqlite_kv_io *pIo; /* IO methods: MUST be first */ - /* Subclasses will typically add additional fields */ -}; -/* - * Key/Value Storage Engine Virtual Method Table. - * - * Key/Value storage engine methods is defined by an instance of the following - * object. - * Registration of a Key/Value storage engine at run-time is done via [unqlite_lib_config()] - * with a configuration verb set to UNQLITE_LIB_CONFIG_STORAGE_ENGINE. - */ -struct unqlite_kv_methods -{ - const char *zName; /* Storage engine name [i.e. Hash, B+tree, LSM, R-tree, Mem, etc.]*/ - int szKv; /* 'unqlite_kv_engine' subclass size */ - int szCursor; /* 'unqlite_kv_cursor' subclass size */ - int iVersion; /* Structure version, currently 1 */ - /* Storage engine methods */ - int (*xInit)(unqlite_kv_engine *,int iPageSize); - void (*xRelease)(unqlite_kv_engine *); - int (*xConfig)(unqlite_kv_engine *,int op,va_list ap); - int (*xOpen)(unqlite_kv_engine *,pgno); - int (*xReplace)( - unqlite_kv_engine *, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ); - int (*xAppend)( - unqlite_kv_engine *, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ); - void (*xCursorInit)(unqlite_kv_cursor *); - int (*xSeek)(unqlite_kv_cursor *,const void *pKey,int nByte,int iPos); /* Mandatory */ - int (*xFirst)(unqlite_kv_cursor *); - int (*xLast)(unqlite_kv_cursor *); - int (*xValid)(unqlite_kv_cursor *); - int (*xNext)(unqlite_kv_cursor *); - int (*xPrev)(unqlite_kv_cursor *); - int (*xDelete)(unqlite_kv_cursor *); - int (*xKeyLength)(unqlite_kv_cursor *,int *); - int (*xKey)(unqlite_kv_cursor *,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); - int (*xDataLength)(unqlite_kv_cursor *,unqlite_int64 *); - int (*xData)(unqlite_kv_cursor *,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); - void (*xReset)(unqlite_kv_cursor *); - void (*xCursorRelease)(unqlite_kv_cursor *); -}; -/* - * UnQLite journal file suffix. - */ -#ifndef UNQLITE_JOURNAL_FILE_SUFFIX -#define UNQLITE_JOURNAL_FILE_SUFFIX "_unqlite_journal" -#endif -/* - * Call Context - Error Message Serverity Level. - * - * The following constans are the allowed severity level that can - * passed as the second argument to the [unqlite_context_throw_error()] or - * [unqlite_context_throw_error_format()] interfaces. - * Refer to the official documentation for additional information. - */ -#define UNQLITE_CTX_ERR 1 /* Call context error such as unexpected number of arguments, invalid types and so on. */ -#define UNQLITE_CTX_WARNING 2 /* Call context Warning */ -#define UNQLITE_CTX_NOTICE 3 /* Call context Notice */ -/* - * C-API-REF: Please refer to the official documentation for interfaces - * purpose and expected parameters. - */ - -/* Database Engine Handle */ -UNQLITE_APIEXPORT int unqlite_open(unqlite **ppDB,const char *zFilename,unsigned int iMode); -UNQLITE_APIEXPORT int unqlite_config(unqlite *pDb,int nOp,...); -UNQLITE_APIEXPORT int unqlite_close(unqlite *pDb); - -/* Key/Value (KV) Store Interfaces */ -UNQLITE_APIEXPORT int unqlite_kv_store(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen); -UNQLITE_APIEXPORT int unqlite_kv_append(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen); -UNQLITE_APIEXPORT int unqlite_kv_store_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...); -UNQLITE_APIEXPORT int unqlite_kv_append_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...); -UNQLITE_APIEXPORT int unqlite_kv_fetch(unqlite *pDb,const void *pKey,int nKeyLen,void *pBuf,unqlite_int64 /* in|out */*pBufLen); -UNQLITE_APIEXPORT int unqlite_kv_fetch_callback(unqlite *pDb,const void *pKey, - int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_kv_delete(unqlite *pDb,const void *pKey,int nKeyLen); -UNQLITE_APIEXPORT int unqlite_kv_config(unqlite *pDb,int iOp,...); - -/* Document (JSON) Store Interfaces powered by the Jx9 Scripting Language */ -UNQLITE_APIEXPORT int unqlite_compile(unqlite *pDb,const char *zJx9,int nByte,unqlite_vm **ppOut); -UNQLITE_APIEXPORT int unqlite_compile_file(unqlite *pDb,const char *zPath,unqlite_vm **ppOut); -UNQLITE_APIEXPORT int unqlite_vm_config(unqlite_vm *pVm,int iOp,...); -UNQLITE_APIEXPORT int unqlite_vm_exec(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_reset(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_release(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_dump(unqlite_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData); -UNQLITE_APIEXPORT unqlite_value * unqlite_vm_extract_variable(unqlite_vm *pVm,const char *zVarname); - -/* Cursor Iterator Interfaces */ -UNQLITE_APIEXPORT int unqlite_kv_cursor_init(unqlite *pDb,unqlite_kv_cursor **ppOut); -UNQLITE_APIEXPORT int unqlite_kv_cursor_release(unqlite *pDb,unqlite_kv_cursor *pCur); -UNQLITE_APIEXPORT int unqlite_kv_cursor_seek(unqlite_kv_cursor *pCursor,const void *pKey,int nKeyLen,int iPos); -UNQLITE_APIEXPORT int unqlite_kv_cursor_first_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_last_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_valid_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_next_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_prev_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_key(unqlite_kv_cursor *pCursor,void *pBuf,int *pnByte); -UNQLITE_APIEXPORT int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_kv_cursor_data(unqlite_kv_cursor *pCursor,void *pBuf,unqlite_int64 *pnData); -UNQLITE_APIEXPORT int unqlite_kv_cursor_data_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_kv_cursor_delete_entry(unqlite_kv_cursor *pCursor); -UNQLITE_APIEXPORT int unqlite_kv_cursor_reset(unqlite_kv_cursor *pCursor); - -/* Manual Transaction Manager */ -UNQLITE_APIEXPORT int unqlite_begin(unqlite *pDb); -UNQLITE_APIEXPORT int unqlite_commit(unqlite *pDb); -UNQLITE_APIEXPORT int unqlite_rollback(unqlite *pDb); - -/* Utility interfaces */ -UNQLITE_APIEXPORT int unqlite_util_load_mmaped_file(const char *zFile,void **ppMap,unqlite_int64 *pFileSize); -UNQLITE_APIEXPORT int unqlite_util_release_mmaped_file(void *pMap,unqlite_int64 iFileSize); -UNQLITE_APIEXPORT int unqlite_util_random_string(unqlite *pDb,char *zBuf,unsigned int buf_size); -UNQLITE_APIEXPORT unsigned int unqlite_util_random_num(unqlite *pDb); - -/* In-process extending interfaces */ -UNQLITE_APIEXPORT int unqlite_create_function(unqlite_vm *pVm,const char *zName,int (*xFunc)(unqlite_context *,int,unqlite_value **),void *pUserData); -UNQLITE_APIEXPORT int unqlite_delete_function(unqlite_vm *pVm, const char *zName); -UNQLITE_APIEXPORT int unqlite_create_constant(unqlite_vm *pVm,const char *zName,void (*xExpand)(unqlite_value *, void *),void *pUserData); -UNQLITE_APIEXPORT int unqlite_delete_constant(unqlite_vm *pVm, const char *zName); - -/* On Demand Object allocation interfaces */ -UNQLITE_APIEXPORT unqlite_value * unqlite_vm_new_scalar(unqlite_vm *pVm); -UNQLITE_APIEXPORT unqlite_value * unqlite_vm_new_array(unqlite_vm *pVm); -UNQLITE_APIEXPORT int unqlite_vm_release_value(unqlite_vm *pVm,unqlite_value *pValue); -UNQLITE_APIEXPORT unqlite_value * unqlite_context_new_scalar(unqlite_context *pCtx); -UNQLITE_APIEXPORT unqlite_value * unqlite_context_new_array(unqlite_context *pCtx); -UNQLITE_APIEXPORT void unqlite_context_release_value(unqlite_context *pCtx,unqlite_value *pValue); - -/* Dynamically Typed Value Object Management Interfaces */ -UNQLITE_APIEXPORT int unqlite_value_int(unqlite_value *pVal, int iValue); -UNQLITE_APIEXPORT int unqlite_value_int64(unqlite_value *pVal, unqlite_int64 iValue); -UNQLITE_APIEXPORT int unqlite_value_bool(unqlite_value *pVal, int iBool); -UNQLITE_APIEXPORT int unqlite_value_null(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_double(unqlite_value *pVal, double Value); -UNQLITE_APIEXPORT int unqlite_value_string(unqlite_value *pVal, const char *zString, int nLen); -UNQLITE_APIEXPORT int unqlite_value_string_format(unqlite_value *pVal, const char *zFormat,...); -UNQLITE_APIEXPORT int unqlite_value_reset_string_cursor(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_resource(unqlite_value *pVal, void *pUserData); -UNQLITE_APIEXPORT int unqlite_value_release(unqlite_value *pVal); - -/* Foreign Function Parameter Values */ -UNQLITE_APIEXPORT int unqlite_value_to_int(unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_value_to_bool(unqlite_value *pValue); -UNQLITE_APIEXPORT unqlite_int64 unqlite_value_to_int64(unqlite_value *pValue); -UNQLITE_APIEXPORT double unqlite_value_to_double(unqlite_value *pValue); -UNQLITE_APIEXPORT const char * unqlite_value_to_string(unqlite_value *pValue, int *pLen); -UNQLITE_APIEXPORT void * unqlite_value_to_resource(unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_value_compare(unqlite_value *pLeft, unqlite_value *pRight, int bStrict); - -/* Setting The Result Of A Foreign Function */ -UNQLITE_APIEXPORT int unqlite_result_int(unqlite_context *pCtx, int iValue); -UNQLITE_APIEXPORT int unqlite_result_int64(unqlite_context *pCtx, unqlite_int64 iValue); -UNQLITE_APIEXPORT int unqlite_result_bool(unqlite_context *pCtx, int iBool); -UNQLITE_APIEXPORT int unqlite_result_double(unqlite_context *pCtx, double Value); -UNQLITE_APIEXPORT int unqlite_result_null(unqlite_context *pCtx); -UNQLITE_APIEXPORT int unqlite_result_string(unqlite_context *pCtx, const char *zString, int nLen); -UNQLITE_APIEXPORT int unqlite_result_string_format(unqlite_context *pCtx, const char *zFormat, ...); -UNQLITE_APIEXPORT int unqlite_result_value(unqlite_context *pCtx, unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_result_resource(unqlite_context *pCtx, void *pUserData); - -/* Dynamically Typed Value Object Query Interfaces */ -UNQLITE_APIEXPORT int unqlite_value_is_int(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_float(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_bool(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_string(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_null(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_numeric(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_callable(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_scalar(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_json_array(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_json_object(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_resource(unqlite_value *pVal); -UNQLITE_APIEXPORT int unqlite_value_is_empty(unqlite_value *pVal); - -/* JSON Array/Object Management Interfaces */ -UNQLITE_APIEXPORT unqlite_value * unqlite_array_fetch(unqlite_value *pArray, const char *zKey, int nByte); -UNQLITE_APIEXPORT int unqlite_array_walk(unqlite_value *pArray, int (*xWalk)(unqlite_value *, unqlite_value *, void *), void *pUserData); -UNQLITE_APIEXPORT int unqlite_array_add_elem(unqlite_value *pArray, unqlite_value *pKey, unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_array_add_strkey_elem(unqlite_value *pArray, const char *zKey, unqlite_value *pValue); -UNQLITE_APIEXPORT int unqlite_array_count(unqlite_value *pArray); - -/* Call Context Handling Interfaces */ -UNQLITE_APIEXPORT int unqlite_context_output(unqlite_context *pCtx, const char *zString, int nLen); -UNQLITE_APIEXPORT int unqlite_context_output_format(unqlite_context *pCtx,const char *zFormat, ...); -UNQLITE_APIEXPORT int unqlite_context_throw_error(unqlite_context *pCtx, int iErr, const char *zErr); -UNQLITE_APIEXPORT int unqlite_context_throw_error_format(unqlite_context *pCtx, int iErr, const char *zFormat, ...); -UNQLITE_APIEXPORT unsigned int unqlite_context_random_num(unqlite_context *pCtx); -UNQLITE_APIEXPORT int unqlite_context_random_string(unqlite_context *pCtx, char *zBuf, int nBuflen); -UNQLITE_APIEXPORT void * unqlite_context_user_data(unqlite_context *pCtx); -UNQLITE_APIEXPORT int unqlite_context_push_aux_data(unqlite_context *pCtx, void *pUserData); -UNQLITE_APIEXPORT void * unqlite_context_peek_aux_data(unqlite_context *pCtx); -UNQLITE_APIEXPORT unsigned int unqlite_context_result_buf_length(unqlite_context *pCtx); -UNQLITE_APIEXPORT const char * unqlite_function_name(unqlite_context *pCtx); - -/* Call Context Memory Management Interfaces */ -UNQLITE_APIEXPORT void * unqlite_context_alloc_chunk(unqlite_context *pCtx,unsigned int nByte,int ZeroChunk,int AutoRelease); -UNQLITE_APIEXPORT void * unqlite_context_realloc_chunk(unqlite_context *pCtx,void *pChunk,unsigned int nByte); -UNQLITE_APIEXPORT void unqlite_context_free_chunk(unqlite_context *pCtx,void *pChunk); - -/* Global Library Management Interfaces */ -UNQLITE_APIEXPORT int unqlite_lib_config(int nConfigOp,...); -UNQLITE_APIEXPORT int unqlite_lib_init(void); -UNQLITE_APIEXPORT int unqlite_lib_shutdown(void); -UNQLITE_APIEXPORT int unqlite_lib_is_threadsafe(void); -UNQLITE_APIEXPORT const char * unqlite_lib_version(void); -UNQLITE_APIEXPORT const char * unqlite_lib_signature(void); -UNQLITE_APIEXPORT const char * unqlite_lib_ident(void); -UNQLITE_APIEXPORT const char * unqlite_lib_copyright(void); -#ifdef __cplusplus -} -#endif /* __cplusplus */ -#endif /* _UNQLITE_H_ */ -/* - * ---------------------------------------------------------- - * File: jx9.h - * MD5: d23a1e182f596794001533e1d6aa16a0 - * ---------------------------------------------------------- - */ -/* This file was automatically generated. Do not edit (except for compile time directive)! */ -#ifndef _JX9H_ -#define _JX9H_ -/* - * Symisc Jx9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ -/* - * Copyright (C) 2012, 2013 Symisc Systems. 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. Redistributions in any form must be accompanied by information on - * how to obtain complete source code for the JX9 engine and any - * accompanying software that uses the JX9 engine software. - * The source code must either be included in the distribution - * or be available for no more than the cost of distribution plus - * a nominal fee, and must be freely redistributable under reasonable - * conditions. For an executable file, complete source code means - * the source code for all modules it contains.It does not include - * source code for modules or files that typically accompany the major - * components of the operating system on which the executable file runs. - * - * THIS SOFTWARE IS PROVIDED BY SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SYMISC SYSTEMS - * 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. - */ - /* $SymiscID: jx9.h v2.1 UNIX|WIN32/64 2012-09-15 09:43 stable $ */ -#include "unqlite.h" -/* - * Compile time engine version, signature, identification in the symisc source tree - * and copyright notice. - * Each macro have an equivalent C interface associated with it that provide the same - * information but are associated with the library instead of the header file. - * Refer to [jx9_lib_version()], [jx9_lib_signature()], [jx9_lib_ident()] and - * [jx9_lib_copyright()] for more information. - */ -/* - * The JX9_VERSION C preprocessor macroevaluates to a string literal - * that is the jx9 version in the format "X.Y.Z" where X is the major - * version number and Y is the minor version number and Z is the release - * number. - */ -#define JX9_VERSION "1.7.2" -/* - * The JX9_VERSION_NUMBER C preprocessor macro resolves to an integer - * with the value (X*1000000 + Y*1000 + Z) where X, Y, and Z are the same - * numbers used in [JX9_VERSION]. - */ -#define JX9_VERSION_NUMBER 1007002 -/* - * The JX9_SIG C preprocessor macro evaluates to a string - * literal which is the public signature of the jx9 engine. - * This signature could be included for example in a host-application - * generated Server MIME header as follows: - * Server: YourWebServer/x.x Jx9/x.x.x \r\n - */ -#define JX9_SIG "Jx9/1.7.2" -/* - * JX9 identification in the Symisc source tree: - * Each particular check-in of a particular software released - * by symisc systems have an unique identifier associated with it. - * This macro hold the one associated with jx9. - */ -#define JX9_IDENT "jx9:d217a6e8c7f10fb35a8becb2793101fd2036aeb7" -/* - * Copyright notice. - * If you have any questions about the licensing situation, please - * visit http://jx9.symisc.net/licensing.html - * or contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - */ -#define JX9_COPYRIGHT "Copyright (C) Symisc Systems 2012-2013, http://jx9.symisc.net/" - -/* Forward declaration to public objects */ -typedef struct jx9_io_stream jx9_io_stream; -typedef struct jx9_context jx9_context; -typedef struct jx9_value jx9_value; -typedef struct jx9_vfs jx9_vfs; -typedef struct jx9_vm jx9_vm; -typedef struct jx9 jx9; - -#include "unqlite.h" - -#if !defined( UNQLITE_ENABLE_JX9_HASH_FUNC ) -#define JX9_DISABLE_HASH_FUNC -#endif /* UNQLITE_ENABLE_JX9_HASH_FUNC */ -#ifdef UNQLITE_ENABLE_THREADS -#define JX9_ENABLE_THREADS -#endif /* UNQLITE_ENABLE_THREADS */ -/* Standard JX9 return values */ -#define JX9_OK SXRET_OK /* Successful result */ -/* beginning-of-error-codes */ -#define JX9_NOMEM UNQLITE_NOMEM /* Out of memory */ -#define JX9_ABORT UNQLITE_ABORT /* Foreign Function request operation abort/Another thread have released this instance */ -#define JX9_IO_ERR UNQLITE_IOERR /* IO error */ -#define JX9_CORRUPT UNQLITE_CORRUPT /* Corrupt pointer/Unknown configuration option */ -#define JX9_LOOKED UNQLITE_LOCKED /* Forbidden Operation */ -#define JX9_COMPILE_ERR UNQLITE_COMPILE_ERR /* Compilation error */ -#define JX9_VM_ERR UNQLITE_VM_ERR /* Virtual machine error */ -/* end-of-error-codes */ -/* - * If compiling for a processor that lacks floating point - * support, substitute integer for floating-point. - */ -#ifdef JX9_OMIT_FLOATING_POINT -typedef sxi64 jx9_real; -#else -typedef double jx9_real; -#endif -typedef sxi64 jx9_int64; -/* - * Engine Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the JX9 engine. - * These constants must be passed as the second argument to the [jx9_config()] - * interface. - * Each options require a variable number of arguments. - * The [jx9_config()] interface will return JX9_OK on success, any other - * return value indicates failure. - * For a full discussion on the configuration verbs and their expected - * parameters, please refer to this page: - * http://jx9.symisc.net/c_api_func.html#jx9_config - */ -#define JX9_CONFIG_ERR_ABORT 1 /* RESERVED FOR FUTURE USE */ -#define JX9_CONFIG_ERR_LOG 2 /* TWO ARGUMENTS: const char **pzBuf, int *pLen */ -/* - * Virtual Machine Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the JX9 Virtual machine. - * These constants must be passed as the second argument to the [jx9_vm_config()] - * interface. - * Each options require a variable number of arguments. - * The [jx9_vm_config()] interface will return JX9_OK on success, any other return - * value indicates failure. - * There are many options but the most importants are: JX9_VM_CONFIG_OUTPUT which install - * a VM output consumer callback, JX9_VM_CONFIG_HTTP_REQUEST which parse and register - * a HTTP request and JX9_VM_CONFIG_ARGV_ENTRY which populate the $argv array. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://jx9.symisc.net/c_api_func.html#jx9_vm_config - */ -#define JX9_VM_CONFIG_OUTPUT UNQLITE_VM_CONFIG_OUTPUT /* TWO ARGUMENTS: int (*xConsumer)(const void *pOut, unsigned int nLen, void *pUserData), void *pUserData */ -#define JX9_VM_CONFIG_IMPORT_PATH UNQLITE_VM_CONFIG_IMPORT_PATH /* ONE ARGUMENT: const char *zIncludePath */ -#define JX9_VM_CONFIG_ERR_REPORT UNQLITE_VM_CONFIG_ERR_REPORT /* NO ARGUMENTS: Report all run-time errors in the VM output */ -#define JX9_VM_CONFIG_RECURSION_DEPTH UNQLITE_VM_CONFIG_RECURSION_DEPTH /* ONE ARGUMENT: int nMaxDepth */ -#define JX9_VM_OUTPUT_LENGTH UNQLITE_VM_OUTPUT_LENGTH /* ONE ARGUMENT: unsigned int *pLength */ -#define JX9_VM_CONFIG_CREATE_VAR UNQLITE_VM_CONFIG_CREATE_VAR /* TWO ARGUMENTS: const char *zName, jx9_value *pValue */ -#define JX9_VM_CONFIG_HTTP_REQUEST UNQLITE_VM_CONFIG_HTTP_REQUEST /* TWO ARGUMENTS: const char *zRawRequest, int nRequestLength */ -#define JX9_VM_CONFIG_SERVER_ATTR UNQLITE_VM_CONFIG_SERVER_ATTR /* THREE ARGUMENTS: const char *zKey, const char *zValue, int nLen */ -#define JX9_VM_CONFIG_ENV_ATTR UNQLITE_VM_CONFIG_ENV_ATTR /* THREE ARGUMENTS: const char *zKey, const char *zValue, int nLen */ -#define JX9_VM_CONFIG_EXEC_VALUE UNQLITE_VM_CONFIG_EXEC_VALUE /* ONE ARGUMENT: jx9_value **ppValue */ -#define JX9_VM_CONFIG_IO_STREAM UNQLITE_VM_CONFIG_IO_STREAM /* ONE ARGUMENT: const jx9_io_stream *pStream */ -#define JX9_VM_CONFIG_ARGV_ENTRY UNQLITE_VM_CONFIG_ARGV_ENTRY /* ONE ARGUMENT: const char *zValue */ -#define JX9_VM_CONFIG_EXTRACT_OUTPUT UNQLITE_VM_CONFIG_EXTRACT_OUTPUT /* TWO ARGUMENTS: const void **ppOut, unsigned int *pOutputLen */ -/* - * Global Library Configuration Commands. - * - * The following set of constants are the available configuration verbs that can - * be used by the host-application to configure the whole library. - * These constants must be passed as the first argument to the [jx9_lib_config()] - * interface. - * Each options require a variable number of arguments. - * The [jx9_lib_config()] interface will return JX9_OK on success, any other return - * value indicates failure. - * Notes: - * The default configuration is recommended for most applications and so the call to - * [jx9_lib_config()] is usually not necessary. It is provided to support rare - * applications with unusual needs. - * The [jx9_lib_config()] interface is not threadsafe. The application must insure that - * no other [jx9_*()] interfaces are invoked by other threads while [jx9_lib_config()] - * is running. Furthermore, [jx9_lib_config()] may only be invoked prior to library - * initialization using [jx9_lib_init()] or [jx9_init()] or after shutdown - * by [jx9_lib_shutdown()]. If [jx9_lib_config()] is called after [jx9_lib_init()] - * or [jx9_init()] and before [jx9_lib_shutdown()] then it will return jx9LOCKED. - * For a full discussion on the configuration verbs and their expected parameters, please - * refer to this page: - * http://jx9.symisc.net/c_api_func.html#Global_Library_Management_Interfaces - */ -#define JX9_LIB_CONFIG_USER_MALLOC 1 /* ONE ARGUMENT: const SyMemMethods *pMemMethods */ -#define JX9_LIB_CONFIG_MEM_ERR_CALLBACK 2 /* TWO ARGUMENTS: int (*xMemError)(void *), void *pUserData */ -#define JX9_LIB_CONFIG_USER_MUTEX 3 /* ONE ARGUMENT: const SyMutexMethods *pMutexMethods */ -#define JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE 4 /* NO ARGUMENTS */ -#define JX9_LIB_CONFIG_THREAD_LEVEL_MULTI 5 /* NO ARGUMENTS */ -#define JX9_LIB_CONFIG_VFS 6 /* ONE ARGUMENT: const jx9_vfs *pVfs */ -/* - * Call Context - Error Message Serverity Level. - */ -#define JX9_CTX_ERR UNQLITE_CTX_ERR /* Call context error such as unexpected number of arguments, invalid types and so on. */ -#define JX9_CTX_WARNING UNQLITE_CTX_WARNING /* Call context Warning */ -#define JX9_CTX_NOTICE UNQLITE_CTX_NOTICE /* Call context Notice */ -/* Current VFS structure version*/ -#define JX9_VFS_VERSION 2 -/* - * JX9 Virtual File System (VFS). - * - * An instance of the jx9_vfs object defines the interface between the JX9 core - * and the underlying operating system. The "vfs" in the name of the object stands - * for "virtual file system". The vfs is used to implement JX9 system functions - * such as mkdir(), chdir(), stat(), get_user_name() and many more. - * The value of the iVersion field is initially 2 but may be larger in future versions - * of JX9. - * Additional fields may be appended to this object when the iVersion value is increased. - * Only a single vfs can be registered within the JX9 core. Vfs registration is done - * using the jx9_lib_config() interface with a configuration verb set to JX9_LIB_CONFIG_VFS. - * Note that Windows and UNIX (Linux, FreeBSD, Solaris, Mac OS X, etc.) users does not have to - * worry about registering and installing a vfs since JX9 come with a built-in vfs for these - * platforms which implement most the methods defined below. - * Host-application running on exotic systems (ie: Other than Windows and UNIX systems) must - * register their own vfs in order to be able to use and call JX9 system functions. - * Also note that the jx9_compile_file() interface depend on the xMmap() method of the underlying - * vfs which mean that this method must be available (Always the case using the built-in VFS) - * in order to use this interface. - * Developers wishing to implement their own vfs an contact symisc systems to obtain - * the JX9 VFS C/C++ Specification manual. - */ -struct jx9_vfs -{ - const char *zName; /* Underlying VFS name [i.e: FreeBSD/Linux/Windows...] */ - int iVersion; /* Current VFS structure version [default 2] */ - /* Directory functions */ - int (*xChdir)(const char *); /* Change directory */ - int (*xChroot)(const char *); /* Change the root directory */ - int (*xGetcwd)(jx9_context *); /* Get the current working directory */ - int (*xMkdir)(const char *, int, int); /* Make directory */ - int (*xRmdir)(const char *); /* Remove directory */ - int (*xIsdir)(const char *); /* Tells whether the filename is a directory */ - int (*xRename)(const char *, const char *); /* Renames a file or directory */ - int (*xRealpath)(const char *, jx9_context *); /* Return canonicalized absolute pathname*/ - /* Systems functions */ - int (*xSleep)(unsigned int); /* Delay execution in microseconds */ - int (*xUnlink)(const char *); /* Deletes a file */ - int (*xFileExists)(const char *); /* Checks whether a file or directory exists */ - int (*xChmod)(const char *, int); /* Changes file mode */ - int (*xChown)(const char *, const char *); /* Changes file owner */ - int (*xChgrp)(const char *, const char *); /* Changes file group */ - jx9_int64 (*xFreeSpace)(const char *); /* Available space on filesystem or disk partition */ - jx9_int64 (*xTotalSpace)(const char *); /* Total space on filesystem or disk partition */ - jx9_int64 (*xFileSize)(const char *); /* Gets file size */ - jx9_int64 (*xFileAtime)(const char *); /* Gets last access time of file */ - jx9_int64 (*xFileMtime)(const char *); /* Gets file modification time */ - jx9_int64 (*xFileCtime)(const char *); /* Gets inode change time of file */ - int (*xStat)(const char *, jx9_value *, jx9_value *); /* Gives information about a file */ - int (*xlStat)(const char *, jx9_value *, jx9_value *); /* Gives information about a file */ - int (*xIsfile)(const char *); /* Tells whether the filename is a regular file */ - int (*xIslink)(const char *); /* Tells whether the filename is a symbolic link */ - int (*xReadable)(const char *); /* Tells whether a file exists and is readable */ - int (*xWritable)(const char *); /* Tells whether the filename is writable */ - int (*xExecutable)(const char *); /* Tells whether the filename is executable */ - int (*xFiletype)(const char *, jx9_context *); /* Gets file type [i.e: fifo, dir, file..] */ - int (*xGetenv)(const char *, jx9_context *); /* Gets the value of an environment variable */ - int (*xSetenv)(const char *, const char *); /* Sets the value of an environment variable */ - int (*xTouch)(const char *, jx9_int64, jx9_int64); /* Sets access and modification time of file */ - int (*xMmap)(const char *, void **, jx9_int64 *); /* Read-only memory map of the whole file */ - void (*xUnmap)(void *, jx9_int64); /* Unmap a memory view */ - int (*xLink)(const char *, const char *, int); /* Create hard or symbolic link */ - int (*xUmask)(int); /* Change the current umask */ - void (*xTempDir)(jx9_context *); /* Get path of the temporary directory */ - unsigned int (*xProcessId)(void); /* Get running process ID */ - int (*xUid)(void); /* user ID of the process */ - int (*xGid)(void); /* group ID of the process */ - void (*xUsername)(jx9_context *); /* Running username */ - int (*xExec)(const char *, jx9_context *); /* Execute an external program */ -}; -/* Current JX9 IO stream structure version. */ -#define JX9_IO_STREAM_VERSION 1 -/* - * Possible open mode flags that can be passed to the xOpen() routine - * of the underlying IO stream device . - * Refer to the JX9 IO Stream C/C++ specification manual (http://jx9.symisc.net/io_stream_spec.html) - * for additional information. - */ -#define JX9_IO_OPEN_RDONLY 0x001 /* Read-only open */ -#define JX9_IO_OPEN_WRONLY 0x002 /* Write-only open */ -#define JX9_IO_OPEN_RDWR 0x004 /* Read-write open. */ -#define JX9_IO_OPEN_CREATE 0x008 /* If the file does not exist it will be created */ -#define JX9_IO_OPEN_TRUNC 0x010 /* Truncate the file to zero length */ -#define JX9_IO_OPEN_APPEND 0x020 /* Append mode.The file offset is positioned at the end of the file */ -#define JX9_IO_OPEN_EXCL 0x040 /* Ensure that this call creates the file, the file must not exist before */ -#define JX9_IO_OPEN_BINARY 0x080 /* Simple hint: Data is binary */ -#define JX9_IO_OPEN_TEMP 0x100 /* Simple hint: Temporary file */ -#define JX9_IO_OPEN_TEXT 0x200 /* Simple hint: Data is textual */ -/* - * JX9 IO Stream Device. - * - * An instance of the jx9_io_stream object defines the interface between the JX9 core - * and the underlying stream device. - * A stream is a smart mechanism for generalizing file, network, data compression - * and other IO operations which share a common set of functions using an abstracted - * unified interface. - * A stream device is additional code which tells the stream how to handle specific - * protocols/encodings. For example, the http device knows how to translate a URL - * into an HTTP/1.1 request for a file on a remote server. - * JX9 come with two built-in IO streams device: - * The file:// stream which perform very efficient disk IO and the jx9:// stream - * which is a special stream that allow access various I/O streams (See the JX9 official - * documentation for more information on this stream). - * A stream is referenced as: scheme://target - * scheme(string) - The name of the wrapper to be used. Examples include: file, http, https, ftp, - * ftps, compress.zlib, compress.bz2, and jx9. If no wrapper is specified, the function default - * is used (typically file://). - * target - Depends on the device used. For filesystem related streams this is typically a path - * and filename of the desired file.For network related streams this is typically a hostname, often - * with a path appended. - * IO stream devices are registered using a call to jx9_vm_config() with a configuration verb - * set to JX9_VM_CONFIG_IO_STREAM. - * Currently the JX9 development team is working on the implementation of the http:// and ftp:// - * IO stream protocols. These devices will be available in the next major release of the JX9 engine. - * Developers wishing to implement their own IO stream devices must understand and follow - * The JX9 IO Stream C/C++ specification manual (http://jx9.symisc.net/io_stream_spec.html). - */ -struct jx9_io_stream -{ - const char *zName; /* Underlying stream name [i.e: file/http/zip/jx9, ..] */ - int iVersion; /* IO stream structure version [default 1]*/ - int (*xOpen)(const char *, int, jx9_value *, void **); /* Open handle*/ - int (*xOpenDir)(const char *, jx9_value *, void **); /* Open directory handle */ - void (*xClose)(void *); /* Close file handle */ - void (*xCloseDir)(void *); /* Close directory handle */ - jx9_int64 (*xRead)(void *, void *, jx9_int64); /* Read from the open stream */ - int (*xReadDir)(void *, jx9_context *); /* Read entry from directory handle */ - jx9_int64 (*xWrite)(void *, const void *, jx9_int64); /* Write to the open stream */ - int (*xSeek)(void *, jx9_int64, int); /* Seek on the open stream */ - int (*xLock)(void *, int); /* Lock/Unlock the open stream */ - void (*xRewindDir)(void *); /* Rewind directory handle */ - jx9_int64 (*xTell)(void *); /* Current position of the stream read/write pointer */ - int (*xTrunc)(void *, jx9_int64); /* Truncates the open stream to a given length */ - int (*xSync)(void *); /* Flush open stream data */ - int (*xStat)(void *, jx9_value *, jx9_value *); /* Stat an open stream handle */ -}; -/* - * C-API-REF: Please refer to the official documentation for interfaces - * purpose and expected parameters. - */ -/* Engine Handling Interfaces */ -JX9_PRIVATE int jx9_init(jx9 **ppEngine); -/*JX9_PRIVATE int jx9_config(jx9 *pEngine, int nConfigOp, ...);*/ -JX9_PRIVATE int jx9_release(jx9 *pEngine); -/* Compile Interfaces */ -JX9_PRIVATE int jx9_compile(jx9 *pEngine, const char *zSource, int nLen, jx9_vm **ppOutVm); -JX9_PRIVATE int jx9_compile_file(jx9 *pEngine, const char *zFilePath, jx9_vm **ppOutVm); -/* Virtual Machine Handling Interfaces */ -JX9_PRIVATE int jx9_vm_config(jx9_vm *pVm, int iConfigOp, ...); -/*JX9_PRIVATE int jx9_vm_exec(jx9_vm *pVm, int *pExitStatus);*/ -/*JX9_PRIVATE jx9_value * jx9_vm_extract_variable(jx9_vm *pVm,const char *zVarname);*/ -/*JX9_PRIVATE int jx9_vm_reset(jx9_vm *pVm);*/ -JX9_PRIVATE int jx9_vm_release(jx9_vm *pVm); -/*JX9_PRIVATE int jx9_vm_dump_v2(jx9_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData);*/ -/* In-process Extending Interfaces */ -JX9_PRIVATE int jx9_create_function(jx9_vm *pVm, const char *zName, int (*xFunc)(jx9_context *, int, jx9_value **), void *pUserData); -/*JX9_PRIVATE int jx9_delete_function(jx9_vm *pVm, const char *zName);*/ -JX9_PRIVATE int jx9_create_constant(jx9_vm *pVm, const char *zName, void (*xExpand)(jx9_value *, void *), void *pUserData); -/*JX9_PRIVATE int jx9_delete_constant(jx9_vm *pVm, const char *zName);*/ -/* Foreign Function Parameter Values */ -JX9_PRIVATE int jx9_value_to_int(jx9_value *pValue); -JX9_PRIVATE int jx9_value_to_bool(jx9_value *pValue); -JX9_PRIVATE jx9_int64 jx9_value_to_int64(jx9_value *pValue); -JX9_PRIVATE double jx9_value_to_double(jx9_value *pValue); -JX9_PRIVATE const char * jx9_value_to_string(jx9_value *pValue, int *pLen); -JX9_PRIVATE void * jx9_value_to_resource(jx9_value *pValue); -JX9_PRIVATE int jx9_value_compare(jx9_value *pLeft, jx9_value *pRight, int bStrict); -/* Setting The Result Of A Foreign Function */ -JX9_PRIVATE int jx9_result_int(jx9_context *pCtx, int iValue); -JX9_PRIVATE int jx9_result_int64(jx9_context *pCtx, jx9_int64 iValue); -JX9_PRIVATE int jx9_result_bool(jx9_context *pCtx, int iBool); -JX9_PRIVATE int jx9_result_double(jx9_context *pCtx, double Value); -JX9_PRIVATE int jx9_result_null(jx9_context *pCtx); -JX9_PRIVATE int jx9_result_string(jx9_context *pCtx, const char *zString, int nLen); -JX9_PRIVATE int jx9_result_string_format(jx9_context *pCtx, const char *zFormat, ...); -JX9_PRIVATE int jx9_result_value(jx9_context *pCtx, jx9_value *pValue); -JX9_PRIVATE int jx9_result_resource(jx9_context *pCtx, void *pUserData); -/* Call Context Handling Interfaces */ -JX9_PRIVATE int jx9_context_output(jx9_context *pCtx, const char *zString, int nLen); -/*JX9_PRIVATE int jx9_context_output_format(jx9_context *pCtx, const char *zFormat, ...);*/ -JX9_PRIVATE int jx9_context_throw_error(jx9_context *pCtx, int iErr, const char *zErr); -JX9_PRIVATE int jx9_context_throw_error_format(jx9_context *pCtx, int iErr, const char *zFormat, ...); -JX9_PRIVATE unsigned int jx9_context_random_num(jx9_context *pCtx); -JX9_PRIVATE int jx9_context_random_string(jx9_context *pCtx, char *zBuf, int nBuflen); -JX9_PRIVATE void * jx9_context_user_data(jx9_context *pCtx); -JX9_PRIVATE int jx9_context_push_aux_data(jx9_context *pCtx, void *pUserData); -JX9_PRIVATE void * jx9_context_peek_aux_data(jx9_context *pCtx); -JX9_PRIVATE void * jx9_context_pop_aux_data(jx9_context *pCtx); -JX9_PRIVATE unsigned int jx9_context_result_buf_length(jx9_context *pCtx); -JX9_PRIVATE const char * jx9_function_name(jx9_context *pCtx); -/* Call Context Memory Management Interfaces */ -JX9_PRIVATE void * jx9_context_alloc_chunk(jx9_context *pCtx, unsigned int nByte, int ZeroChunk, int AutoRelease); -JX9_PRIVATE void * jx9_context_realloc_chunk(jx9_context *pCtx, void *pChunk, unsigned int nByte); -JX9_PRIVATE void jx9_context_free_chunk(jx9_context *pCtx, void *pChunk); -/* On Demand Dynamically Typed Value Object allocation interfaces */ -JX9_PRIVATE jx9_value * jx9_new_scalar(jx9_vm *pVm); -JX9_PRIVATE jx9_value * jx9_new_array(jx9_vm *pVm); -JX9_PRIVATE int jx9_release_value(jx9_vm *pVm, jx9_value *pValue); -JX9_PRIVATE jx9_value * jx9_context_new_scalar(jx9_context *pCtx); -JX9_PRIVATE jx9_value * jx9_context_new_array(jx9_context *pCtx); -JX9_PRIVATE void jx9_context_release_value(jx9_context *pCtx, jx9_value *pValue); -/* Dynamically Typed Value Object Management Interfaces */ -JX9_PRIVATE int jx9_value_int(jx9_value *pVal, int iValue); -JX9_PRIVATE int jx9_value_int64(jx9_value *pVal, jx9_int64 iValue); -JX9_PRIVATE int jx9_value_bool(jx9_value *pVal, int iBool); -JX9_PRIVATE int jx9_value_null(jx9_value *pVal); -JX9_PRIVATE int jx9_value_double(jx9_value *pVal, double Value); -JX9_PRIVATE int jx9_value_string(jx9_value *pVal, const char *zString, int nLen); -JX9_PRIVATE int jx9_value_string_format(jx9_value *pVal, const char *zFormat, ...); -JX9_PRIVATE int jx9_value_reset_string_cursor(jx9_value *pVal); -JX9_PRIVATE int jx9_value_resource(jx9_value *pVal, void *pUserData); -JX9_PRIVATE int jx9_value_release(jx9_value *pVal); -/* JSON Array/Object Management Interfaces */ -JX9_PRIVATE jx9_value * jx9_array_fetch(jx9_value *pArray, const char *zKey, int nByte); -JX9_PRIVATE int jx9_array_walk(jx9_value *pArray, int (*xWalk)(jx9_value *, jx9_value *, void *), void *pUserData); -JX9_PRIVATE int jx9_array_add_elem(jx9_value *pArray, jx9_value *pKey, jx9_value *pValue); -JX9_PRIVATE int jx9_array_add_strkey_elem(jx9_value *pArray, const char *zKey, jx9_value *pValue); -JX9_PRIVATE unsigned int jx9_array_count(jx9_value *pArray); -/* Dynamically Typed Value Object Query Interfaces */ -JX9_PRIVATE int jx9_value_is_int(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_float(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_bool(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_string(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_null(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_numeric(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_callable(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_scalar(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_json_array(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_json_object(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_resource(jx9_value *pVal); -JX9_PRIVATE int jx9_value_is_empty(jx9_value *pVal); -/* Global Library Management Interfaces */ -/*JX9_PRIVATE int jx9_lib_init(void);*/ -JX9_PRIVATE int jx9_lib_config(int nConfigOp, ...); -JX9_PRIVATE int jx9_lib_shutdown(void); -/*JX9_PRIVATE int jx9_lib_is_threadsafe(void);*/ -/*JX9_PRIVATE const char * jx9_lib_version(void);*/ -JX9_PRIVATE const char * jx9_lib_signature(void); -/*JX9_PRIVATE const char * jx9_lib_ident(void);*/ -/*JX9_PRIVATE const char * jx9_lib_copyright(void);*/ - -#endif /* _JX9H_ */ - -/* - * ---------------------------------------------------------- - * File: jx9Int.h - * MD5: fb8dffc8ba1425a139091aa145067e16 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: jx9Int.h v1.9 FreeBSD 2012-08-13 23:25 devel $ */ -#ifndef __JX9INT_H__ -#define __JX9INT_H__ -/* Internal interface definitions for JX9. */ -#ifdef JX9_AMALGAMATION -#ifndef JX9_PRIVATE -/* Marker for routines not intended for external use */ -#define JX9_PRIVATE static -#endif /* JX9_PRIVATE */ -#else -#define JX9_PRIVATE -#include "jx9.h" -#endif -#ifndef JX9_PI -/* Value of PI */ -#define JX9_PI 3.1415926535898 -#endif -/* - * Constants for the largest and smallest possible 64-bit signed integers. - * These macros are designed to work correctly on both 32-bit and 64-bit - * compilers. - */ -#ifndef LARGEST_INT64 -#define LARGEST_INT64 (0xffffffff|(((sxi64)0x7fffffff)<<32)) -#endif -#ifndef SMALLEST_INT64 -#define SMALLEST_INT64 (((sxi64)-1) - LARGEST_INT64) -#endif -/* Forward declaration of private structures */ -typedef struct jx9_foreach_info jx9_foreach_info; -typedef struct jx9_foreach_step jx9_foreach_step; -typedef struct jx9_hashmap_node jx9_hashmap_node; -typedef struct jx9_hashmap jx9_hashmap; -/* Symisc Standard types */ -#if !defined(SYMISC_STD_TYPES) -#define SYMISC_STD_TYPES -#ifdef __WINNT__ -/* Disable nuisance warnings on Borland compilers */ -#if defined(__BORLANDC__) -#pragma warn -rch /* unreachable code */ -#pragma warn -ccc /* Condition is always true or false */ -#pragma warn -aus /* Assigned value is never used */ -#pragma warn -csu /* Comparing signed and unsigned */ -#pragma warn -spa /* Suspicious pointer arithmetic */ -#endif -#endif -typedef signed char sxi8; /* signed char */ -typedef unsigned char sxu8; /* unsigned char */ -typedef signed short int sxi16; /* 16 bits(2 bytes) signed integer */ -typedef unsigned short int sxu16; /* 16 bits(2 bytes) unsigned integer */ -typedef int sxi32; /* 32 bits(4 bytes) integer */ -typedef unsigned int sxu32; /* 32 bits(4 bytes) unsigned integer */ -typedef long sxptr; -typedef unsigned long sxuptr; -typedef long sxlong; -typedef unsigned long sxulong; -typedef sxi32 sxofft; -typedef sxi64 sxofft64; -typedef long double sxlongreal; -typedef double sxreal; -#define SXI8_HIGH 0x7F -#define SXU8_HIGH 0xFF -#define SXI16_HIGH 0x7FFF -#define SXU16_HIGH 0xFFFF -#define SXI32_HIGH 0x7FFFFFFF -#define SXU32_HIGH 0xFFFFFFFF -#define SXI64_HIGH 0x7FFFFFFFFFFFFFFF -#define SXU64_HIGH 0xFFFFFFFFFFFFFFFF -#if !defined(TRUE) -#define TRUE 1 -#endif -#if !defined(FALSE) -#define FALSE 0 -#endif -/* - * The following macros are used to cast pointers to integers and - * integers to pointers. - */ -#if defined(__PTRDIFF_TYPE__) -# define SX_INT_TO_PTR(X) ((void*)(__PTRDIFF_TYPE__)(X)) -# define SX_PTR_TO_INT(X) ((int)(__PTRDIFF_TYPE__)(X)) -#elif !defined(__GNUC__) -# define SX_INT_TO_PTR(X) ((void*)&((char*)0)[X]) -# define SX_PTR_TO_INT(X) ((int)(((char*)X)-(char*)0)) -#else -# define SX_INT_TO_PTR(X) ((void*)(X)) -# define SX_PTR_TO_INT(X) ((int)(X)) -#endif -#define SXMIN(a, b) ((a < b) ? (a) : (b)) -#define SXMAX(a, b) ((a < b) ? (b) : (a)) -#endif /* SYMISC_STD_TYPES */ -/* Symisc Run-time API private definitions */ -#if !defined(SYMISC_PRIVATE_DEFS) -#define SYMISC_PRIVATE_DEFS - -typedef sxi32 (*ProcRawStrCmp)(const SyString *, const SyString *); -#define SyStringData(RAW) ((RAW)->zString) -#define SyStringLength(RAW) ((RAW)->nByte) -#define SyStringInitFromBuf(RAW, ZBUF, NLEN){\ - (RAW)->zString = (const char *)ZBUF;\ - (RAW)->nByte = (sxu32)(NLEN);\ -} -#define SyStringUpdatePtr(RAW, NBYTES){\ - if( NBYTES > (RAW)->nByte ){\ - (RAW)->nByte = 0;\ - }else{\ - (RAW)->zString += NBYTES;\ - (RAW)->nByte -= NBYTES;\ - }\ -} -#define SyStringDupPtr(RAW1, RAW2)\ - (RAW1)->zString = (RAW2)->zString;\ - (RAW1)->nByte = (RAW2)->nByte; - -#define SyStringTrimLeadingChar(RAW, CHAR)\ - while((RAW)->nByte > 0 && (RAW)->zString[0] == CHAR ){\ - (RAW)->zString++;\ - (RAW)->nByte--;\ - } -#define SyStringTrimTrailingChar(RAW, CHAR)\ - while((RAW)->nByte > 0 && (RAW)->zString[(RAW)->nByte - 1] == CHAR){\ - (RAW)->nByte--;\ - } -#define SyStringCmp(RAW1, RAW2, xCMP)\ - (((RAW1)->nByte == (RAW2)->nByte) ? xCMP((RAW1)->zString, (RAW2)->zString, (RAW2)->nByte) : (sxi32)((RAW1)->nByte - (RAW2)->nByte)) - -#define SyStringCmp2(RAW1, RAW2, xCMP)\ - (((RAW1)->nByte >= (RAW2)->nByte) ? xCMP((RAW1)->zString, (RAW2)->zString, (RAW2)->nByte) : (sxi32)((RAW2)->nByte - (RAW1)->nByte)) - -#define SyStringCharCmp(RAW, CHAR) \ - (((RAW)->nByte == sizeof(char)) ? ((RAW)->zString[0] == CHAR ? 0 : CHAR - (RAW)->zString[0]) : ((RAW)->zString[0] == CHAR ? 0 : (RAW)->nByte - sizeof(char))) - -#define SX_ADDR(PTR) ((sxptr)PTR) -#define SX_ARRAYSIZE(X) (sizeof(X)/sizeof(X[0])) -#define SXUNUSED(P) (P = 0) -#define SX_EMPTY(PTR) (PTR == 0) -#define SX_EMPTY_STR(STR) (STR == 0 || STR[0] == 0 ) -typedef struct SyMemBackend SyMemBackend; -typedef struct SyBlob SyBlob; -typedef struct SySet SySet; -/* Standard function signatures */ -typedef sxi32 (*ProcCmp)(const void *, const void *, sxu32); -typedef sxi32 (*ProcPatternMatch)(const char *, sxu32, const char *, sxu32, sxu32 *); -typedef sxi32 (*ProcSearch)(const void *, sxu32, const void *, sxu32, ProcCmp, sxu32 *); -typedef sxu32 (*ProcHash)(const void *, sxu32); -typedef sxi32 (*ProcHashSum)(const void *, sxu32, unsigned char *, sxu32); -typedef sxi32 (*ProcSort)(void *, sxu32, sxu32, ProcCmp); -#define MACRO_LIST_PUSH(Head, Item)\ - Item->pNext = Head;\ - Head = Item; -#define MACRO_LD_PUSH(Head, Item)\ - if( Head == 0 ){\ - Head = Item;\ - }else{\ - Item->pNext = Head;\ - Head->pPrev = Item;\ - Head = Item;\ - } -#define MACRO_LD_REMOVE(Head, Item)\ - if( Head == Item ){\ - Head = Head->pNext;\ - }\ - if( Item->pPrev ){ Item->pPrev->pNext = Item->pNext;}\ - if( Item->pNext ){ Item->pNext->pPrev = Item->pPrev;} -/* - * A generic dynamic set. - */ -struct SySet -{ - SyMemBackend *pAllocator; /* Memory backend */ - void *pBase; /* Base pointer */ - sxu32 nUsed; /* Total number of used slots */ - sxu32 nSize; /* Total number of available slots */ - sxu32 eSize; /* Size of a single slot */ - sxu32 nCursor; /* Loop cursor */ - void *pUserData; /* User private data associated with this container */ -}; -#define SySetBasePtr(S) ((S)->pBase) -#define SySetBasePtrJump(S, OFFT) (&((char *)(S)->pBase)[OFFT*(S)->eSize]) -#define SySetUsed(S) ((S)->nUsed) -#define SySetSize(S) ((S)->nSize) -#define SySetElemSize(S) ((S)->eSize) -#define SySetCursor(S) ((S)->nCursor) -#define SySetGetAllocator(S) ((S)->pAllocator) -#define SySetSetUserData(S, DATA) ((S)->pUserData = DATA) -#define SySetGetUserData(S) ((S)->pUserData) -/* - * A variable length containers for generic data. - */ -struct SyBlob -{ - SyMemBackend *pAllocator; /* Memory backend */ - void *pBlob; /* Base pointer */ - sxu32 nByte; /* Total number of used bytes */ - sxu32 mByte; /* Total number of available bytes */ - sxu32 nFlags; /* Blob internal flags, see below */ -}; -#define SXBLOB_LOCKED 0x01 /* Blob is locked [i.e: Cannot auto grow] */ -#define SXBLOB_STATIC 0x02 /* Not allocated from heap */ -#define SXBLOB_RDONLY 0x04 /* Read-Only data */ - -#define SyBlobFreeSpace(BLOB) ((BLOB)->mByte - (BLOB)->nByte) -#define SyBlobLength(BLOB) ((BLOB)->nByte) -#define SyBlobData(BLOB) ((BLOB)->pBlob) -#define SyBlobCurData(BLOB) ((void*)(&((char*)(BLOB)->pBlob)[(BLOB)->nByte])) -#define SyBlobDataAt(BLOB, OFFT) ((void *)(&((char *)(BLOB)->pBlob)[OFFT])) -#define SyBlobGetAllocator(BLOB) ((BLOB)->pAllocator) - -#define SXMEM_POOL_INCR 3 -#define SXMEM_POOL_NBUCKETS 12 -#define SXMEM_BACKEND_MAGIC 0xBAC3E67D -#define SXMEM_BACKEND_CORRUPT(BACKEND) (BACKEND == 0 || BACKEND->nMagic != SXMEM_BACKEND_MAGIC) - -#define SXMEM_BACKEND_RETRY 3 -/* A memory backend subsystem is defined by an instance of the following structures */ -typedef union SyMemHeader SyMemHeader; -typedef struct SyMemBlock SyMemBlock; -struct SyMemBlock -{ - SyMemBlock *pNext, *pPrev; /* Chain of allocated memory blocks */ -#ifdef UNTRUST - sxu32 nGuard; /* magic number associated with each valid block, so we - * can detect misuse. - */ -#endif -}; -/* - * Header associated with each valid memory pool block. - */ -union SyMemHeader -{ - SyMemHeader *pNext; /* Next chunk of size 1 << (nBucket + SXMEM_POOL_INCR) in the list */ - sxu32 nBucket; /* Bucket index in aPool[] */ -}; -struct SyMemBackend -{ - const SyMutexMethods *pMutexMethods; /* Mutex methods */ - const SyMemMethods *pMethods; /* Memory allocation methods */ - SyMemBlock *pBlocks; /* List of valid memory blocks */ - sxu32 nBlock; /* Total number of memory blocks allocated so far */ - ProcMemError xMemError; /* Out-of memory callback */ - void *pUserData; /* First arg to xMemError() */ - SyMutex *pMutex; /* Per instance mutex */ - sxu32 nMagic; /* Sanity check against misuse */ - SyMemHeader *apPool[SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR]; /* Pool of memory chunks */ -}; -/* Mutex types */ -#define SXMUTEX_TYPE_FAST 1 -#define SXMUTEX_TYPE_RECURSIVE 2 -#define SXMUTEX_TYPE_STATIC_1 3 -#define SXMUTEX_TYPE_STATIC_2 4 -#define SXMUTEX_TYPE_STATIC_3 5 -#define SXMUTEX_TYPE_STATIC_4 6 -#define SXMUTEX_TYPE_STATIC_5 7 -#define SXMUTEX_TYPE_STATIC_6 8 - -#define SyMutexGlobalInit(METHOD){\ - if( (METHOD)->xGlobalInit ){\ - (METHOD)->xGlobalInit();\ - }\ -} -#define SyMutexGlobalRelease(METHOD){\ - if( (METHOD)->xGlobalRelease ){\ - (METHOD)->xGlobalRelease();\ - }\ -} -#define SyMutexNew(METHOD, TYPE) (METHOD)->xNew(TYPE) -#define SyMutexRelease(METHOD, MUTEX){\ - if( MUTEX && (METHOD)->xRelease ){\ - (METHOD)->xRelease(MUTEX);\ - }\ -} -#define SyMutexEnter(METHOD, MUTEX){\ - if( MUTEX ){\ - (METHOD)->xEnter(MUTEX);\ - }\ -} -#define SyMutexTryEnter(METHOD, MUTEX){\ - if( MUTEX && (METHOD)->xTryEnter ){\ - (METHOD)->xTryEnter(MUTEX);\ - }\ -} -#define SyMutexLeave(METHOD, MUTEX){\ - if( MUTEX ){\ - (METHOD)->xLeave(MUTEX);\ - }\ -} -/* Comparison, byte swap, byte copy macros */ -#define SX_MACRO_FAST_CMP(X1, X2, SIZE, RC){\ - register unsigned char *r1 = (unsigned char *)X1;\ - register unsigned char *r2 = (unsigned char *)X2;\ - register sxu32 LEN = SIZE;\ - for(;;){\ - if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\ - if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\ - if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\ - if( !LEN ){ break; }if( r1[0] != r2[0] ){ break; } r1++; r2++; LEN--;\ - }\ - RC = !LEN ? 0 : r1[0] - r2[0];\ -} -#define SX_MACRO_FAST_MEMCPY(SRC, DST, SIZ){\ - register unsigned char *xSrc = (unsigned char *)SRC;\ - register unsigned char *xDst = (unsigned char *)DST;\ - register sxu32 xLen = SIZ;\ - for(;;){\ - if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\ - if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\ - if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\ - if( !xLen ){ break; }xDst[0] = xSrc[0]; xDst++; xSrc++; --xLen;\ - }\ -} -#define SX_MACRO_BYTE_SWAP(X, Y, Z){\ - register unsigned char *s = (unsigned char *)X;\ - register unsigned char *d = (unsigned char *)Y;\ - sxu32 ZLong = Z; \ - sxi32 c; \ - for(;;){\ - if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\ - if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\ - if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\ - if(!ZLong){ break; } c = s[0] ; s[0] = d[0]; d[0] = (unsigned char)c; s++; d++; --ZLong;\ - }\ -} -#define SX_MSEC_PER_SEC (1000) /* Millisec per seconds */ -#define SX_USEC_PER_SEC (1000000) /* Microsec per seconds */ -#define SX_NSEC_PER_SEC (1000000000) /* Nanosec per seconds */ -#endif /* SYMISC_PRIVATE_DEFS */ -/* Symisc Run-time API auxiliary definitions */ -#if !defined(SYMISC_PRIVATE_AUX_DEFS) -#define SYMISC_PRIVATE_AUX_DEFS - -typedef struct SyHashEntry_Pr SyHashEntry_Pr; -typedef struct SyHashEntry SyHashEntry; -typedef struct SyHash SyHash; -/* - * Each public hashtable entry is represented by an instance - * of the following structure. - */ -struct SyHashEntry -{ - const void *pKey; /* Hash key */ - sxu32 nKeyLen; /* Key length */ - void *pUserData; /* User private data */ -}; -#define SyHashEntryGetUserData(ENTRY) ((ENTRY)->pUserData) -#define SyHashEntryGetKey(ENTRY) ((ENTRY)->pKey) -/* Each active hashtable is identified by an instance of the following structure */ -struct SyHash -{ - SyMemBackend *pAllocator; /* Memory backend */ - ProcHash xHash; /* Hash function */ - ProcCmp xCmp; /* Comparison function */ - SyHashEntry_Pr *pList, *pCurrent; /* Linked list of hash entries user for linear traversal */ - sxu32 nEntry; /* Total number of entries */ - SyHashEntry_Pr **apBucket; /* Hash buckets */ - sxu32 nBucketSize; /* Current bucket size */ -}; -#define SXHASH_BUCKET_SIZE 16 /* Initial bucket size: must be a power of two */ -#define SXHASH_FILL_FACTOR 3 -/* Hash access macro */ -#define SyHashFunc(HASH) ((HASH)->xHash) -#define SyHashCmpFunc(HASH) ((HASH)->xCmp) -#define SyHashTotalEntry(HASH) ((HASH)->nEntry) -#define SyHashGetPool(HASH) ((HASH)->pAllocator) -/* - * An instance of the following structure define a single context - * for an Pseudo Random Number Generator. - * - * Nothing in this file or anywhere else in the library does any kind of - * encryption. The RC4 algorithm is being used as a PRNG (pseudo-random - * number generator) not as an encryption device. - * This implementation is taken from the SQLite3 source tree. - */ -typedef struct SyPRNGCtx SyPRNGCtx; -struct SyPRNGCtx -{ - sxu8 i, j; /* State variables */ - unsigned char s[256]; /* State variables */ - sxu16 nMagic; /* Sanity check */ - }; -typedef sxi32 (*ProcRandomSeed)(void *, unsigned int, void *); -/* High resolution timer.*/ -typedef struct sytime sytime; -struct sytime -{ - long tm_sec; /* seconds */ - long tm_usec; /* microseconds */ -}; -/* Forward declaration */ -typedef struct SyStream SyStream; -typedef struct SyToken SyToken; -typedef struct SyLex SyLex; -/* - * Tokenizer callback signature. - */ -typedef sxi32 (*ProcTokenizer)(SyStream *, SyToken *, void *, void *); -/* - * Each token in the input is represented by an instance - * of the following structure. - */ -struct SyToken -{ - SyString sData; /* Token text and length */ - sxu32 nType; /* Token type */ - sxu32 nLine; /* Token line number */ - void *pUserData; /* User private data associated with this token */ -}; -/* - * During tokenization, information about the state of the input - * stream is held in an instance of the following structure. - */ -struct SyStream -{ - const unsigned char *zInput; /* Complete text of the input */ - const unsigned char *zText; /* Current input we are processing */ - const unsigned char *zEnd; /* End of input marker */ - sxu32 nLine; /* Total number of processed lines */ - sxu32 nIgn; /* Total number of ignored tokens */ - SySet *pSet; /* Token containers */ -}; -/* - * Each lexer is represented by an instance of the following structure. - */ -struct SyLex -{ - SyStream sStream; /* Input stream */ - ProcTokenizer xTokenizer; /* Tokenizer callback */ - void * pUserData; /* Third argument to xTokenizer() */ - SySet *pTokenSet; /* Token set */ -}; -#define SyLexTotalToken(LEX) SySetTotalEntry(&(LEX)->aTokenSet) -#define SyLexTotalLines(LEX) ((LEX)->sStream.nLine) -#define SyLexTotalIgnored(LEX) ((LEX)->sStream.nIgn) -#define XLEX_IN_LEN(STREAM) (sxu32)(STREAM->zEnd - STREAM->zText) -#endif /* SYMISC_PRIVATE_AUX_DEFS */ -/* -** Notes on UTF-8 (According to SQLite3 authors): -** -** Byte-0 Byte-1 Byte-2 Byte-3 Value -** 0xxxxxxx 00000000 00000000 0xxxxxxx -** 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx -** 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx -** 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx -** -*/ -/* -** Assuming zIn points to the first byte of a UTF-8 character, -** advance zIn to point to the first byte of the next UTF-8 character. -*/ -#define SX_JMP_UTF8(zIn, zEnd)\ - while(zIn < zEnd && (((unsigned char)zIn[0] & 0xc0) == 0x80) ){ zIn++; } -#define SX_WRITE_UTF8(zOut, c) { \ - if( c<0x00080 ){ \ - *zOut++ = (sxu8)(c&0xFF); \ - }else if( c<0x00800 ){ \ - *zOut++ = 0xC0 + (sxu8)((c>>6)&0x1F); \ - *zOut++ = 0x80 + (sxu8)(c & 0x3F); \ - }else if( c<0x10000 ){ \ - *zOut++ = 0xE0 + (sxu8)((c>>12)&0x0F); \ - *zOut++ = 0x80 + (sxu8)((c>>6) & 0x3F); \ - *zOut++ = 0x80 + (sxu8)(c & 0x3F); \ - }else{ \ - *zOut++ = 0xF0 + (sxu8)((c>>18) & 0x07); \ - *zOut++ = 0x80 + (sxu8)((c>>12) & 0x3F); \ - *zOut++ = 0x80 + (sxu8)((c>>6) & 0x3F); \ - *zOut++ = 0x80 + (sxu8)(c & 0x3F); \ - } \ -} -/* Rely on the standard ctype */ -#include -#define SyToUpper(c) toupper(c) -#define SyToLower(c) tolower(c) -#define SyisUpper(c) isupper(c) -#define SyisLower(c) islower(c) -#define SyisSpace(c) isspace(c) -#define SyisBlank(c) isspace(c) -#define SyisAlpha(c) isalpha(c) -#define SyisDigit(c) isdigit(c) -#define SyisHex(c) isxdigit(c) -#define SyisPrint(c) isprint(c) -#define SyisPunct(c) ispunct(c) -#define SyisSpec(c) iscntrl(c) -#define SyisCtrl(c) iscntrl(c) -#define SyisAscii(c) isascii(c) -#define SyisAlphaNum(c) isalnum(c) -#define SyisGraph(c) isgraph(c) -#define SyDigToHex(c) "0123456789ABCDEF"[c & 0x0F] -#define SyDigToInt(c) ((c < 0xc0 && SyisDigit(c))? (c - '0') : 0 ) -#define SyCharToUpper(c) ((c < 0xc0 && SyisLower(c))? SyToUpper(c) : c) -#define SyCharToLower(c) ((c < 0xc0 && SyisUpper(c))? SyToLower(c) : c) -/* Remove white space/NUL byte from a raw string */ -#define SyStringLeftTrim(RAW)\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && SyisSpace((RAW)->zString[0])){\ - (RAW)->nByte--;\ - (RAW)->zString++;\ - } -#define SyStringLeftTrimSafe(RAW)\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && ((RAW)->zString[0] == 0 || SyisSpace((RAW)->zString[0]))){\ - (RAW)->nByte--;\ - (RAW)->zString++;\ - } -#define SyStringRightTrim(RAW)\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && SyisSpace((RAW)->zString[(RAW)->nByte - 1])){\ - (RAW)->nByte--;\ - } -#define SyStringRightTrimSafe(RAW)\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && \ - (( RAW)->zString[(RAW)->nByte - 1] == 0 || SyisSpace((RAW)->zString[(RAW)->nByte - 1]))){\ - (RAW)->nByte--;\ - } - -#define SyStringFullTrim(RAW)\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && SyisSpace((RAW)->zString[0])){\ - (RAW)->nByte--;\ - (RAW)->zString++;\ - }\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && SyisSpace((RAW)->zString[(RAW)->nByte - 1])){\ - (RAW)->nByte--;\ - } -#define SyStringFullTrimSafe(RAW)\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[0] < 0xc0 && \ - ( (RAW)->zString[0] == 0 || SyisSpace((RAW)->zString[0]))){\ - (RAW)->nByte--;\ - (RAW)->zString++;\ - }\ - while((RAW)->nByte > 0 && (unsigned char)(RAW)->zString[(RAW)->nByte - 1] < 0xc0 && \ - ( (RAW)->zString[(RAW)->nByte - 1] == 0 || SyisSpace((RAW)->zString[(RAW)->nByte - 1]))){\ - (RAW)->nByte--;\ - } -#ifndef JX9_DISABLE_BUILTIN_FUNC -/* - * An XML raw text, CDATA, tag name and son is parsed out and stored - * in an instance of the following structure. - */ -typedef struct SyXMLRawStr SyXMLRawStr; -struct SyXMLRawStr -{ - const char *zString; /* Raw text [UTF-8 ENCODED EXCEPT CDATA] [NOT NULL TERMINATED] */ - sxu32 nByte; /* Text length */ - sxu32 nLine; /* Line number this text occurs */ -}; -/* - * Event callback signatures. - */ -typedef sxi32 (*ProcXMLStartTagHandler)(SyXMLRawStr *, SyXMLRawStr *, sxu32, SyXMLRawStr *, void *); -typedef sxi32 (*ProcXMLTextHandler)(SyXMLRawStr *, void *); -typedef sxi32 (*ProcXMLEndTagHandler)(SyXMLRawStr *, SyXMLRawStr *, void *); -typedef sxi32 (*ProcXMLPIHandler)(SyXMLRawStr *, SyXMLRawStr *, void *); -typedef sxi32 (*ProcXMLDoctypeHandler)(SyXMLRawStr *, void *); -typedef sxi32 (*ProcXMLSyntaxErrorHandler)(const char *, int, SyToken *, void *); -typedef sxi32 (*ProcXMLStartDocument)(void *); -typedef sxi32 (*ProcXMLNameSpaceStart)(SyXMLRawStr *, SyXMLRawStr *, void *); -typedef sxi32 (*ProcXMLNameSpaceEnd)(SyXMLRawStr *, void *); -typedef sxi32 (*ProcXMLEndDocument)(void *); -/* XML processing control flags */ -#define SXML_ENABLE_NAMESPACE 0x01 /* Parse XML with namespace support enbaled */ -#define SXML_ENABLE_QUERY 0x02 /* Not used */ -#define SXML_OPTION_CASE_FOLDING 0x04 /* Controls whether case-folding is enabled for this XML parser */ -#define SXML_OPTION_SKIP_TAGSTART 0x08 /* Specify how many characters should be skipped in the beginning of a tag name.*/ -#define SXML_OPTION_SKIP_WHITE 0x10 /* Whether to skip values consisting of whitespace characters. */ -#define SXML_OPTION_TARGET_ENCODING 0x20 /* Default encoding: UTF-8 */ -/* XML error codes */ -enum xml_err_code{ - SXML_ERROR_NONE = 1, - SXML_ERROR_NO_MEMORY, - SXML_ERROR_SYNTAX, - SXML_ERROR_NO_ELEMENTS, - SXML_ERROR_INVALID_TOKEN, - SXML_ERROR_UNCLOSED_TOKEN, - SXML_ERROR_PARTIAL_CHAR, - SXML_ERROR_TAG_MISMATCH, - SXML_ERROR_DUPLICATE_ATTRIBUTE, - SXML_ERROR_JUNK_AFTER_DOC_ELEMENT, - SXML_ERROR_PARAM_ENTITY_REF, - SXML_ERROR_UNDEFINED_ENTITY, - SXML_ERROR_RECURSIVE_ENTITY_REF, - SXML_ERROR_ASYNC_ENTITY, - SXML_ERROR_BAD_CHAR_REF, - SXML_ERROR_BINARY_ENTITY_REF, - SXML_ERROR_ATTRIBUTE_EXTERNAL_ENTITY_REF, - SXML_ERROR_MISPLACED_XML_PI, - SXML_ERROR_UNKNOWN_ENCODING, - SXML_ERROR_INCORRECT_ENCODING, - SXML_ERROR_UNCLOSED_CDATA_SECTION, - SXML_ERROR_EXTERNAL_ENTITY_HANDLING -}; -/* Each active XML SAX parser is represented by an instance - * of the following structure. - */ -typedef struct SyXMLParser SyXMLParser; -struct SyXMLParser -{ - SyMemBackend *pAllocator; /* Memory backend */ - void *pUserData; /* User private data forwarded varbatim by the XML parser - * as the last argument to the users callbacks. - */ - SyHash hns; /* Namespace hashtable */ - SySet sToken; /* XML tokens */ - SyLex sLex; /* Lexical analyzer */ - sxi32 nFlags; /* Control flags */ - /* User callbacks */ - ProcXMLStartTagHandler xStartTag; /* Start element handler */ - ProcXMLEndTagHandler xEndTag; /* End element handler */ - ProcXMLTextHandler xRaw; /* Raw text/CDATA handler */ - ProcXMLDoctypeHandler xDoctype; /* DOCTYPE handler */ - ProcXMLPIHandler xPi; /* Processing instruction (PI) handler*/ - ProcXMLSyntaxErrorHandler xError; /* Error handler */ - ProcXMLStartDocument xStartDoc; /* StartDoc handler */ - ProcXMLEndDocument xEndDoc; /* EndDoc handler */ - ProcXMLNameSpaceStart xNameSpace; /* Namespace declaration handler */ - ProcXMLNameSpaceEnd xNameSpaceEnd; /* End namespace declaration handler */ -}; -/* - * -------------- - * Archive extractor: - * -------------- - * Each open ZIP/TAR archive is identified by an instance of the following structure. - * That is, a process can open one or more archives and manipulates them in thread safe - * way by simply working with pointers to the following structure. - * Each entry in the archive is remembered in a hashtable. - * Lookup is very fast and entry with the same name are chained together. - */ - typedef struct SyArchiveEntry SyArchiveEntry; - typedef struct SyArchive SyArchive; - struct SyArchive - { - SyMemBackend *pAllocator; /* Memory backend */ - SyArchiveEntry *pCursor; /* Cursor for linear traversal of archive entries */ - SyArchiveEntry *pList; /* Pointer to the List of the loaded archive */ - SyArchiveEntry **apHash; /* Hashtable for archive entry */ - ProcRawStrCmp xCmp; /* Hash comparison function */ - ProcHash xHash; /* Hash Function */ - sxu32 nSize; /* Hashtable size */ - sxu32 nEntry; /* Total number of entries in the zip/tar archive */ - sxu32 nLoaded; /* Total number of entries loaded in memory */ - sxu32 nCentralOfft; /* Central directory offset(ZIP only. Otherwise Zero) */ - sxu32 nCentralSize; /* Central directory size(ZIP only. Otherwise Zero) */ - void *pUserData; /* Upper layer private data */ - sxu32 nMagic; /* Sanity check */ - - }; -#define SXARCH_MAGIC 0xDEAD635A -#define SXARCH_INVALID(ARCH) (ARCH == 0 || ARCH->nMagic != SXARCH_MAGIC) -#define SXARCH_ENTRY_INVALID(ENTRY) (ENTRY == 0 || ENTRY->nMagic != SXARCH_MAGIC) -#define SyArchiveHashFunc(ARCH) (ARCH)->xHash -#define SyArchiveCmpFunc(ARCH) (ARCH)->xCmp -#define SyArchiveUserData(ARCH) (ARCH)->pUserData -#define SyArchiveSetUserData(ARCH, DATA) (ARCH)->pUserData = DATA -/* - * Each loaded archive record is identified by an instance - * of the following structure. - */ - struct SyArchiveEntry - { - sxu32 nByte; /* Contents size before compression */ - sxu32 nByteCompr; /* Contents size after compression */ - sxu32 nReadCount; /* Read counter */ - sxu32 nCrc; /* Contents CRC32 */ - Sytm sFmt; /* Last-modification time */ - sxu32 nOfft; /* Data offset. */ - sxu16 nComprMeth; /* Compression method 0 == stored/8 == deflated and so on (see appnote.txt)*/ - sxu16 nExtra; /* Extra size if any */ - SyString sFileName; /* entry name & length */ - sxu32 nDup; /* Total number of entries with the same name */ - SyArchiveEntry *pNextHash, *pPrevHash; /* Hash collision chains */ - SyArchiveEntry *pNextName; /* Next entry with the same name */ - SyArchiveEntry *pNext, *pPrev; /* Next and previous entry in the list */ - sxu32 nHash; /* Hash of the entry name */ - void *pUserData; /* User data */ - sxu32 nMagic; /* Sanity check */ - }; - /* - * Extra flags for extending the file local header - */ -#define SXZIP_EXTRA_TIMESTAMP 0x001 /* Extended UNIX timestamp */ -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -#ifndef JX9_DISABLE_HASH_FUNC -/* MD5 context */ -typedef struct MD5Context MD5Context; -struct MD5Context { - sxu32 buf[4]; - sxu32 bits[2]; - unsigned char in[64]; -}; -/* SHA1 context */ -typedef struct SHA1Context SHA1Context; -struct SHA1Context { - unsigned int state[5]; - unsigned int count[2]; - unsigned char buffer[64]; -}; -#endif /* JX9_DISABLE_HASH_FUNC */ -/* JX9 private declaration */ -/* - * Memory Objects. - * Internally, the JX9 virtual machine manipulates nearly all JX9 values - * [i.e: string, int, float, resource, object, bool, null] as jx9_values structures. - * Each jx9_values struct may cache multiple representations (string, integer etc.) - * of the same value. - */ -struct jx9_value -{ - union{ - jx9_real rVal; /* Real value */ - sxi64 iVal; /* Integer value */ - void *pOther; /* Other values (Object, Array, Resource, Namespace, etc.) */ - }x; - sxi32 iFlags; /* Control flags (see below) */ - jx9_vm *pVm; /* VM this instance belong */ - SyBlob sBlob; /* String values */ - sxu32 nIdx; /* Object index in the global pool */ -}; -/* Allowed value types. - */ -#define MEMOBJ_STRING 0x001 /* Memory value is a UTF-8 string */ -#define MEMOBJ_INT 0x002 /* Memory value is an integer */ -#define MEMOBJ_REAL 0x004 /* Memory value is a real number */ -#define MEMOBJ_BOOL 0x008 /* Memory value is a boolean */ -#define MEMOBJ_NULL 0x020 /* Memory value is NULL */ -#define MEMOBJ_HASHMAP 0x040 /* Memory value is a hashmap (JSON representation of Array and Objects) */ -#define MEMOBJ_RES 0x100 /* Memory value is a resource [User private data] */ -/* Mask of all known types */ -#define MEMOBJ_ALL (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_RES) -/* Scalar variables - * According to the JX9 language reference manual - * Scalar variables are those containing an integer, float, string or boolean. - * Types array, object and resource are not scalar. - */ -#define MEMOBJ_SCALAR (MEMOBJ_STRING|MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL) -/* - * The following macro clear the current jx9_value type and replace - * it with the given one. - */ -#define MemObjSetType(OBJ, TYPE) ((OBJ)->iFlags = ((OBJ)->iFlags&~MEMOBJ_ALL)|TYPE) -/* jx9_value cast method signature */ -typedef sxi32 (*ProcMemObjCast)(jx9_value *); -/* Forward reference */ -typedef struct jx9_output_consumer jx9_output_consumer; -typedef struct jx9_user_func jx9_user_func; -typedef struct jx9_conf jx9_conf; -/* - * An instance of the following structure store the default VM output - * consumer and it's private data. - * Client-programs can register their own output consumer callback - * via the [JX9_VM_CONFIG_OUTPUT] configuration directive. - * Please refer to the official documentation for more information - * on how to register an output consumer callback. - */ -struct jx9_output_consumer -{ - ProcConsumer xConsumer; /* VM output consumer routine */ - void *pUserData; /* Third argument to xConsumer() */ - ProcConsumer xDef; /* Default output consumer routine */ - void *pDefData; /* Third argument to xDef() */ -}; -/* - * JX9 engine [i.e: jx9 instance] configuration is stored in - * an instance of the following structure. - * Please refer to the official documentation for more information - * on how to configure your jx9 engine instance. - */ -struct jx9_conf -{ - ProcConsumer xErr; /* Compile-time error consumer callback */ - void *pErrData; /* Third argument to xErr() */ - SyBlob sErrConsumer; /* Default error consumer */ -}; -/* - * Signature of the C function responsible of expanding constant values. - */ -typedef void (*ProcConstant)(jx9_value *, void *); -/* - * Each registered constant [i.e: __TIME__, __DATE__, JX9_OS, INT_MAX, etc.] is stored - * in an instance of the following structure. - * Please refer to the official documentation for more information - * on how to create/install foreign constants. - */ -typedef struct jx9_constant jx9_constant; -struct jx9_constant -{ - SyString sName; /* Constant name */ - ProcConstant xExpand; /* Function responsible of expanding constant value */ - void *pUserData; /* Last argument to xExpand() */ -}; -typedef struct jx9_aux_data jx9_aux_data; -/* - * Auxiliary data associated with each foreign function is stored - * in a stack of the following structure. - * Note that automatic tracked chunks are also stored in an instance - * of this structure. - */ -struct jx9_aux_data -{ - void *pAuxData; /* Aux data */ -}; -/* Foreign functions signature */ -typedef int (*ProcHostFunction)(jx9_context *, int, jx9_value **); -/* - * Each installed foreign function is recored in an instance of the following - * structure. - * Please refer to the official documentation for more information on how - * to create/install foreign functions. - */ -struct jx9_user_func -{ - jx9_vm *pVm; /* VM that own this instance */ - SyString sName; /* Foreign function name */ - ProcHostFunction xFunc; /* Implementation of the foreign function */ - void *pUserData; /* User private data [Refer to the official documentation for more information]*/ - SySet aAux; /* Stack of auxiliary data [Refer to the official documentation for more information]*/ -}; -/* - * The 'context' argument for an installable function. A pointer to an - * instance of this structure is the first argument to the routines used - * implement the foreign functions. - */ -struct jx9_context -{ - jx9_user_func *pFunc; /* Function information. */ - jx9_value *pRet; /* Return value is stored here. */ - SySet sVar; /* Container of dynamically allocated jx9_values - * [i.e: Garbage collection purposes.] - */ - SySet sChunk; /* Track dynamically allocated chunks [jx9_aux_data instance]. - * [i.e: Garbage collection purposes.] - */ - jx9_vm *pVm; /* Virtual machine that own this context */ - sxi32 iFlags; /* Call flags */ -}; -/* Hashmap control flags */ -#define HASHMAP_JSON_OBJECT 0x001 /* Hashmap represent JSON Object*/ -/* - * Each hashmap entry [i.e: array(4, 5, 6)] is recorded in an instance - * of the following structure. - */ -struct jx9_hashmap_node -{ - jx9_hashmap *pMap; /* Hashmap that own this instance */ - sxi32 iType; /* Node type */ - union{ - sxi64 iKey; /* Int key */ - SyBlob sKey; /* Blob key */ - }xKey; - sxi32 iFlags; /* Control flags */ - sxu32 nHash; /* Key hash value */ - sxu32 nValIdx; /* Value stored in this node */ - jx9_hashmap_node *pNext, *pPrev; /* Link to other entries [i.e: linear traversal] */ - jx9_hashmap_node *pNextCollide, *pPrevCollide; /* Collision chain */ -}; -/* - * Each active hashmap aka array in the JX9 jargon is represented - * by an instance of the following structure. - */ -struct jx9_hashmap -{ - jx9_vm *pVm; /* VM that own this instance */ - jx9_hashmap_node **apBucket; /* Hash bucket */ - jx9_hashmap_node *pFirst; /* First inserted entry */ - jx9_hashmap_node *pLast; /* Last inserted entry */ - jx9_hashmap_node *pCur; /* Current entry */ - sxu32 nSize; /* Bucket size */ - sxu32 nEntry; /* Total number of inserted entries */ - sxu32 (*xIntHash)(sxi64); /* Hash function for int_keys */ - sxu32 (*xBlobHash)(const void *, sxu32); /* Hash function for blob_keys */ - sxi32 iFlags; /* Hashmap control flags */ - sxi64 iNextIdx; /* Next available automatically assigned index */ - sxi32 iRef; /* Reference count */ -}; -/* An instance of the following structure is the context - * for the FOREACH_STEP/FOREACH_INIT VM instructions. - * Those instructions are used to implement the 'foreach' - * statement. - * This structure is made available to these instructions - * as the P3 operand. - */ -struct jx9_foreach_info -{ - SyString sKey; /* Key name. Empty otherwise*/ - SyString sValue; /* Value name */ - sxi32 iFlags; /* Control flags */ - SySet aStep; /* Stack of steps [i.e: jx9_foreach_step instance] */ -}; -struct jx9_foreach_step -{ - sxi32 iFlags; /* Control flags (see below) */ - /* Iterate on this map*/ - jx9_hashmap *pMap; /* Hashmap [i.e: array in the JX9 jargon] iteration - * Ex: foreach(array(1, 2, 3) as $key=>$value){} - */ - -}; -/* Foreach step control flags */ -#define JX9_4EACH_STEP_KEY 0x001 /* Make Key available */ -/* - * Each JX9 engine is identified by an instance of the following structure. - * Please refer to the official documentation for more information - * on how to configure your JX9 engine instance. - */ -struct jx9 -{ - SyMemBackend sAllocator; /* Low level memory allocation subsystem */ - const jx9_vfs *pVfs; /* Underlying Virtual File System */ - jx9_conf xConf; /* Configuration */ -#if defined(JX9_ENABLE_THREADS) - SyMutex *pMutex; /* Per-engine mutex */ -#endif - jx9_vm *pVms; /* List of active VM */ - sxi32 iVm; /* Total number of active VM */ - jx9 *pNext, *pPrev; /* List of active engines */ - sxu32 nMagic; /* Sanity check against misuse */ -}; -/* Code generation data structures */ -typedef sxi32 (*ProcErrorGen)(void *, sxi32, sxu32, const char *, ...); -typedef struct jx9_expr_node jx9_expr_node; -typedef struct jx9_expr_op jx9_expr_op; -typedef struct jx9_gen_state jx9_gen_state; -typedef struct GenBlock GenBlock; -typedef sxi32 (*ProcLangConstruct)(jx9_gen_state *); -typedef sxi32 (*ProcNodeConstruct)(jx9_gen_state *, sxi32); -/* - * Each supported operator [i.e: +, -, ==, *, %, >>, >=, new, etc.] is represented - * by an instance of the following structure. - * The JX9 parser does not use any external tools and is 100% handcoded. - * That is, the JX9 parser is thread-safe , full reentrant, produce consistant - * compile-time errrors and at least 7 times faster than the standard JX9 parser. - */ -struct jx9_expr_op -{ - SyString sOp; /* String representation of the operator [i.e: "+", "*", "=="...] */ - sxi32 iOp; /* Operator ID */ - sxi32 iPrec; /* Operator precedence: 1 == Highest */ - sxi32 iAssoc; /* Operator associativity (either left, right or non-associative) */ - sxi32 iVmOp; /* VM OP code for this operator [i.e: JX9_OP_EQ, JX9_OP_LT, JX9_OP_MUL...]*/ -}; -/* - * Each expression node is parsed out and recorded - * in an instance of the following structure. - */ -struct jx9_expr_node -{ - const jx9_expr_op *pOp; /* Operator ID or NULL if literal, constant, variable, function or object method call */ - jx9_expr_node *pLeft; /* Left expression tree */ - jx9_expr_node *pRight; /* Right expression tree */ - SyToken *pStart; /* Stream of tokens that belong to this node */ - SyToken *pEnd; /* End of token stream */ - sxi32 iFlags; /* Node construct flags */ - ProcNodeConstruct xCode; /* C routine responsible of compiling this node */ - SySet aNodeArgs; /* Node arguments. Only used by postfix operators [i.e: function call]*/ - jx9_expr_node *pCond; /* Condition: Only used by the ternary operator '?:' */ -}; -/* Node Construct flags */ -#define EXPR_NODE_PRE_INCR 0x01 /* Pre-icrement/decrement [i.e: ++$i, --$j] node */ -/* - * A block of instructions is recorded in an instance of the following structure. - * This structure is used only during compile-time and have no meaning - * during bytecode execution. - */ -struct GenBlock -{ - jx9_gen_state *pGen; /* State of the code generator */ - GenBlock *pParent; /* Upper block or NULL if global */ - sxu32 nFirstInstr; /* First instruction to execute */ - sxi32 iFlags; /* Block control flags (see below) */ - SySet aJumpFix; /* Jump fixup (JumpFixup instance) */ - void *pUserData; /* Upper layer private data */ - /* The following two fields are used only when compiling - * the 'do..while()' language construct. - */ - sxu8 bPostContinue; /* TRUE when compiling the do..while() statement */ - SySet aPostContFix; /* Post-continue jump fix */ -}; -/* - * Code generator state is remembered in an instance of the following - * structure. We put the information in this structure and pass around - * a pointer to this structure, rather than pass around all of the - * information separately. This helps reduce the number of arguments - * to generator functions. - * This structure is used only during compile-time and have no meaning - * during bytecode execution. - */ -struct jx9_gen_state -{ - jx9_vm *pVm; /* VM that own this instance */ - SyHash hLiteral; /* Constant string Literals table */ - SyHash hNumLiteral; /* Numeric literals table */ - SyHash hVar; /* Collected variable hashtable */ - GenBlock *pCurrent; /* Current processed block */ - GenBlock sGlobal; /* Global block */ - ProcConsumer xErr; /* Error consumer callback */ - void *pErrData; /* Third argument to xErr() */ - SyToken *pIn; /* Current processed token */ - SyToken *pEnd; /* Last token in the stream */ - sxu32 nErr; /* Total number of compilation error */ -}; -/* Forward references */ -typedef struct jx9_vm_func_static_var jx9_vm_func_static_var; -typedef struct jx9_vm_func_arg jx9_vm_func_arg; -typedef struct jx9_vm_func jx9_vm_func; -typedef struct VmFrame VmFrame; -/* - * Each collected function argument is recorded in an instance - * of the following structure. - * Note that as an extension, JX9 implements full type hinting - * which mean that any function can have it's own signature. - * Example: - * function foo(int $a, string $b, float $c, ClassInstance $d){} - * This is how the powerful function overloading mechanism is - * implemented. - * Note that as an extension, JX9 allow function arguments to have - * any complex default value associated with them unlike the standard - * JX9 engine. - * Example: - * function foo(int $a = rand() & 1023){} - * now, when foo is called without arguments [i.e: foo()] the - * $a variable (first parameter) will be set to a random number - * between 0 and 1023 inclusive. - * Refer to the official documentation for more information on this - * mechanism and other extension introduced by the JX9 engine. - */ -struct jx9_vm_func_arg -{ - SyString sName; /* Argument name */ - SySet aByteCode; /* Compiled default value associated with this argument */ - sxu32 nType; /* Type of this argument [i.e: array, int, string, float, object, etc.] */ - sxi32 iFlags; /* Configuration flags */ -}; -/* - * Each static variable is parsed out and remembered in an instance - * of the following structure. - * Note that as an extension, JX9 allow static variable have - * any complex default value associated with them unlike the standard - * JX9 engine. - * Example: - * static $rand_str = 'JX9'.rand_str(3); // Concatenate 'JX9' with - * // a random three characters(English alphabet) - * dump($rand_str); - * //You should see something like this - * string(6 'JX9awt'); - */ -struct jx9_vm_func_static_var -{ - SyString sName; /* Static variable name */ - SySet aByteCode; /* Compiled initialization expression */ - sxu32 nIdx; /* Object index in the global memory object container */ -}; -/* Function configuration flags */ -#define VM_FUNC_ARG_HAS_DEF 0x001 /* Argument has default value associated with it */ -#define VM_FUNC_ARG_IGNORE 0x002 /* Do not install argument in the current frame */ -/* - * Each user defined function is parsed out and stored in an instance - * of the following structure. - * JX9 introduced some powerfull extensions to the JX9 5 programming - * language like function overloading, type hinting, complex default - * arguments values and many more. - * Please refer to the official documentation for more information. - */ -struct jx9_vm_func -{ - SySet aArgs; /* Expected arguments (jx9_vm_func_arg instance) */ - SySet aStatic; /* Static variable (jx9_vm_func_static_var instance) */ - SyString sName; /* Function name */ - SySet aByteCode; /* Compiled function body */ - sxi32 iFlags; /* VM function configuration */ - SyString sSignature; /* Function signature used to implement function overloading - * (Refer to the official docuemntation for more information - * on this powerfull feature) - */ - void *pUserData; /* Upper layer private data associated with this instance */ - jx9_vm_func *pNextName; /* Next VM function with the same name as this one */ -}; -/* Forward reference */ -typedef struct jx9_builtin_constant jx9_builtin_constant; -typedef struct jx9_builtin_func jx9_builtin_func; -/* - * Each built-in foreign function (C function) is stored in an - * instance of the following structure. - * Please refer to the official documentation for more information - * on how to create/install foreign functions. - */ -struct jx9_builtin_func -{ - const char *zName; /* Function name [i.e: strlen(), rand(), array_merge(), etc.]*/ - ProcHostFunction xFunc; /* C routine performing the computation */ -}; -/* - * Each built-in foreign constant is stored in an instance - * of the following structure. - * Please refer to the official documentation for more information - * on how to create/install foreign constants. - */ -struct jx9_builtin_constant -{ - const char *zName; /* Constant name */ - ProcConstant xExpand; /* C routine responsible of expanding constant value*/ -}; -/* - * A single instruction of the virtual machine has an opcode - * and as many as three operands. - * Each VM instruction resulting from compiling a JX9 script - * is stored in an instance of the following structure. - */ -typedef struct VmInstr VmInstr; -struct VmInstr -{ - sxu8 iOp; /* Operation to preform */ - sxi32 iP1; /* First operand */ - sxu32 iP2; /* Second operand (Often the jump destination) */ - void *p3; /* Third operand (Often Upper layer private data) */ -}; -/* Forward reference */ -typedef struct jx9_case_expr jx9_case_expr; -typedef struct jx9_switch jx9_switch; -/* - * Each compiled case block in a swicth statement is compiled - * and stored in an instance of the following structure. - */ -struct jx9_case_expr -{ - SySet aByteCode; /* Compiled body of the case block */ - sxu32 nStart; /* First instruction to execute */ -}; -/* - * Each compiled switch statement is parsed out and stored - * in an instance of the following structure. - */ -struct jx9_switch -{ - SySet aCaseExpr; /* Compile case block */ - sxu32 nOut; /* First instruction to execute after this statement */ - sxu32 nDefault; /* First instruction to execute in the default block */ -}; -/* Assertion flags */ -#define JX9_ASSERT_DISABLE 0x01 /* Disable assertion */ -#define JX9_ASSERT_WARNING 0x02 /* Issue a warning for each failed assertion */ -#define JX9_ASSERT_BAIL 0x04 /* Terminate execution on failed assertions */ -#define JX9_ASSERT_QUIET_EVAL 0x08 /* Not used */ -#define JX9_ASSERT_CALLBACK 0x10 /* Callback to call on failed assertions */ -/* - * An instance of the following structure hold the bytecode instructions - * resulting from compiling a JX9 script. - * This structure contains the complete state of the virtual machine. - */ -struct jx9_vm -{ - SyMemBackend sAllocator; /* Memory backend */ -#if defined(JX9_ENABLE_THREADS) - SyMutex *pMutex; /* Recursive mutex associated with this VM. */ -#endif - jx9 *pEngine; /* Interpreter that own this VM */ - SySet aByteCode; /* Default bytecode container */ - SySet *pByteContainer; /* Current bytecode container */ - VmFrame *pFrame; /* Stack of active frames */ - SyPRNGCtx sPrng; /* PRNG context */ - SySet aMemObj; /* Object allocation table */ - SySet aLitObj; /* Literals allocation table */ - jx9_value *aOps; /* Operand stack */ - SySet aFreeObj; /* Stack of free memory objects */ - SyHash hConstant; /* Host-application and user defined constants container */ - SyHash hHostFunction; /* Host-application installable functions */ - SyHash hFunction; /* Compiled functions */ - SyHash hSuper; /* Global variable */ - SyBlob sConsumer; /* Default VM consumer [i.e Redirect all VM output to this blob] */ - SyBlob sWorker; /* General purpose working buffer */ - SyBlob sArgv; /* $argv[] collector [refer to the [getopt()] implementation for more information] */ - SySet aFiles; /* Stack of processed files */ - SySet aPaths; /* Set of import paths */ - SySet aIncluded; /* Set of included files */ - SySet aIOstream; /* Installed IO stream container */ - const jx9_io_stream *pDefStream; /* Default IO stream [i.e: typically this is the 'file://' stream] */ - jx9_value sExec; /* Compiled script return value [Can be extracted via the JX9_VM_CONFIG_EXEC_VALUE directive]*/ - void *pStdin; /* STDIN IO stream */ - void *pStdout; /* STDOUT IO stream */ - void *pStderr; /* STDERR IO stream */ - int bErrReport; /* TRUE to report all runtime Error/Warning/Notice */ - int nRecursionDepth; /* Current recursion depth */ - int nMaxDepth; /* Maximum allowed recusion depth */ - sxu32 nOutputLen; /* Total number of generated output */ - jx9_output_consumer sVmConsumer; /* Registered output consumer callback */ - int iAssertFlags; /* Assertion flags */ - jx9_value sAssertCallback; /* Callback to call on failed assertions */ - sxi32 iExitStatus; /* Script exit status */ - jx9_gen_state sCodeGen; /* Code generator module */ - jx9_vm *pNext, *pPrev; /* List of active VM's */ - sxu32 nMagic; /* Sanity check against misuse */ -}; -/* - * Allowed value for jx9_vm.nMagic - */ -#define JX9_VM_INIT 0xEA12CD72 /* VM correctly initialized */ -#define JX9_VM_RUN 0xBA851227 /* VM ready to execute JX9 bytecode */ -#define JX9_VM_EXEC 0xCDFE1DAD /* VM executing JX9 bytecode */ -#define JX9_VM_STALE 0xDEAD2BAD /* Stale VM */ -/* - * Error codes according to the JX9 language reference manual. - */ -enum iErrCode -{ - E_ABORT = -1, /* deadliness error, should halt script execution. */ - E_ERROR = 1, /* Fatal run-time errors. These indicate errors that can not be recovered - * from, such as a memory allocation problem. Execution of the script is - * halted. - * The only fatal error under JX9 is an out-of-memory. All others erros - * even a call to undefined function will not halt script execution. - */ - E_WARNING , /* Run-time warnings (non-fatal errors). Execution of the script is not halted. */ - E_PARSE , /* Compile-time parse errors. Parse errors should only be generated by the parser.*/ - E_NOTICE , /* Run-time notices. Indicate that the script encountered something that could - * indicate an error, but could also happen in the normal course of running a script. - */ -}; -/* - * Each VM instruction resulting from compiling a JX9 script is represented - * by one of the following OP codes. - * The program consists of a linear sequence of operations. Each operation - * has an opcode and 3 operands.Operands P1 is an integer. - * Operand P2 is an unsigned integer and operand P3 is a memory address. - * Few opcodes use all 3 operands. - */ -enum jx9_vm_op { - JX9_OP_DONE = 1, /* Done */ - JX9_OP_HALT, /* Halt */ - JX9_OP_LOAD, /* Load memory object */ - JX9_OP_LOADC, /* Load constant */ - JX9_OP_LOAD_IDX, /* Load array entry */ - JX9_OP_LOAD_MAP, /* Load hashmap('array') */ - JX9_OP_NOOP, /* NOOP */ - JX9_OP_JMP, /* Unconditional jump */ - JX9_OP_JZ, /* Jump on zero (FALSE jump) */ - JX9_OP_JNZ, /* Jump on non-zero (TRUE jump) */ - JX9_OP_POP, /* Stack POP */ - JX9_OP_CAT, /* Concatenation */ - JX9_OP_CVT_INT, /* Integer cast */ - JX9_OP_CVT_STR, /* String cast */ - JX9_OP_CVT_REAL, /* Float cast */ - JX9_OP_CALL, /* Function call */ - JX9_OP_UMINUS, /* Unary minus '-'*/ - JX9_OP_UPLUS, /* Unary plus '+'*/ - JX9_OP_BITNOT, /* Bitwise not '~' */ - JX9_OP_LNOT, /* Logical not '!' */ - JX9_OP_MUL, /* Multiplication '*' */ - JX9_OP_DIV, /* Division '/' */ - JX9_OP_MOD, /* Modulus '%' */ - JX9_OP_ADD, /* Add '+' */ - JX9_OP_SUB, /* Sub '-' */ - JX9_OP_SHL, /* Left shift '<<' */ - JX9_OP_SHR, /* Right shift '>>' */ - JX9_OP_LT, /* Less than '<' */ - JX9_OP_LE, /* Less or equal '<=' */ - JX9_OP_GT, /* Greater than '>' */ - JX9_OP_GE, /* Greater or equal '>=' */ - JX9_OP_EQ, /* Equal '==' */ - JX9_OP_NEQ, /* Not equal '!=' */ - JX9_OP_TEQ, /* Type equal '===' */ - JX9_OP_TNE, /* Type not equal '!==' */ - JX9_OP_BAND, /* Bitwise and '&' */ - JX9_OP_BXOR, /* Bitwise xor '^' */ - JX9_OP_BOR, /* Bitwise or '|' */ - JX9_OP_LAND, /* Logical and '&&','and' */ - JX9_OP_LOR, /* Logical or '||','or' */ - JX9_OP_LXOR, /* Logical xor 'xor' */ - JX9_OP_STORE, /* Store Object */ - JX9_OP_STORE_IDX, /* Store indexed object */ - JX9_OP_PULL, /* Stack pull */ - JX9_OP_SWAP, /* Stack swap */ - JX9_OP_YIELD, /* Stack yield */ - JX9_OP_CVT_BOOL, /* Boolean cast */ - JX9_OP_CVT_NUMC, /* Numeric (integer, real or both) type cast */ - JX9_OP_INCR, /* Increment ++ */ - JX9_OP_DECR, /* Decrement -- */ - JX9_OP_ADD_STORE, /* Add and store '+=' */ - JX9_OP_SUB_STORE, /* Sub and store '-=' */ - JX9_OP_MUL_STORE, /* Mul and store '*=' */ - JX9_OP_DIV_STORE, /* Div and store '/=' */ - JX9_OP_MOD_STORE, /* Mod and store '%=' */ - JX9_OP_CAT_STORE, /* Cat and store '.=' */ - JX9_OP_SHL_STORE, /* Shift left and store '>>=' */ - JX9_OP_SHR_STORE, /* Shift right and store '<<=' */ - JX9_OP_BAND_STORE, /* Bitand and store '&=' */ - JX9_OP_BOR_STORE, /* Bitor and store '|=' */ - JX9_OP_BXOR_STORE, /* Bitxor and store '^=' */ - JX9_OP_CONSUME, /* Consume VM output */ - JX9_OP_MEMBER, /* Object member run-time access */ - JX9_OP_UPLINK, /* Run-Time frame link */ - JX9_OP_CVT_NULL, /* NULL cast */ - JX9_OP_CVT_ARRAY, /* Array cast */ - JX9_OP_FOREACH_INIT, /* For each init */ - JX9_OP_FOREACH_STEP, /* For each step */ - JX9_OP_SWITCH /* Switch operation */ -}; -/* -- END-OF INSTRUCTIONS -- */ -/* - * Expression Operators ID. - */ -enum jx9_expr_id { - EXPR_OP_DOT, /* Member access */ - EXPR_OP_DC, /* :: */ - EXPR_OP_SUBSCRIPT, /* []: Subscripting */ - EXPR_OP_FUNC_CALL, /* func_call() */ - EXPR_OP_INCR, /* ++ */ - EXPR_OP_DECR, /* -- */ - EXPR_OP_BITNOT, /* ~ */ - EXPR_OP_UMINUS, /* Unary minus */ - EXPR_OP_UPLUS, /* Unary plus */ - EXPR_OP_TYPECAST, /* Type cast [i.e: (int), (float), (string)...] */ - EXPR_OP_ALT, /* @ */ - EXPR_OP_INSTOF, /* instanceof */ - EXPR_OP_LOGNOT, /* logical not ! */ - EXPR_OP_MUL, /* Multiplication */ - EXPR_OP_DIV, /* division */ - EXPR_OP_MOD, /* Modulus */ - EXPR_OP_ADD, /* Addition */ - EXPR_OP_SUB, /* Substraction */ - EXPR_OP_DDOT, /* Concatenation */ - EXPR_OP_SHL, /* Left shift */ - EXPR_OP_SHR, /* Right shift */ - EXPR_OP_LT, /* Less than */ - EXPR_OP_LE, /* Less equal */ - EXPR_OP_GT, /* Greater than */ - EXPR_OP_GE, /* Greater equal */ - EXPR_OP_EQ, /* Equal == */ - EXPR_OP_NE, /* Not equal != <> */ - EXPR_OP_TEQ, /* Type equal === */ - EXPR_OP_TNE, /* Type not equal !== */ - EXPR_OP_SEQ, /* String equal 'eq' */ - EXPR_OP_SNE, /* String not equal 'ne' */ - EXPR_OP_BAND, /* Biwise and '&' */ - EXPR_OP_REF, /* Reference operator '&' */ - EXPR_OP_XOR, /* bitwise xor '^' */ - EXPR_OP_BOR, /* bitwise or '|' */ - EXPR_OP_LAND, /* Logical and '&&','and' */ - EXPR_OP_LOR, /* Logical or '||','or'*/ - EXPR_OP_LXOR, /* Logical xor 'xor' */ - EXPR_OP_QUESTY, /* Ternary operator '?' */ - EXPR_OP_ASSIGN, /* Assignment '=' */ - EXPR_OP_ADD_ASSIGN, /* Combined operator: += */ - EXPR_OP_SUB_ASSIGN, /* Combined operator: -= */ - EXPR_OP_MUL_ASSIGN, /* Combined operator: *= */ - EXPR_OP_DIV_ASSIGN, /* Combined operator: /= */ - EXPR_OP_MOD_ASSIGN, /* Combined operator: %= */ - EXPR_OP_DOT_ASSIGN, /* Combined operator: .= */ - EXPR_OP_AND_ASSIGN, /* Combined operator: &= */ - EXPR_OP_OR_ASSIGN, /* Combined operator: |= */ - EXPR_OP_XOR_ASSIGN, /* Combined operator: ^= */ - EXPR_OP_SHL_ASSIGN, /* Combined operator: <<= */ - EXPR_OP_SHR_ASSIGN, /* Combined operator: >>= */ - EXPR_OP_COMMA /* Comma expression */ -}; -/* - * Lexer token codes - * The following set of constants are the tokens recognized - * by the lexer when processing JX9 input. - * Important: Token values MUST BE A POWER OF TWO. - */ -#define JX9_TK_INTEGER 0x0000001 /* Integer */ -#define JX9_TK_REAL 0x0000002 /* Real number */ -#define JX9_TK_NUM (JX9_TK_INTEGER|JX9_TK_REAL) /* Numeric token, either integer or real */ -#define JX9_TK_KEYWORD 0x0000004 /* Keyword [i.e: while, for, if, foreach...] */ -#define JX9_TK_ID 0x0000008 /* Alphanumeric or UTF-8 stream */ -#define JX9_TK_DOLLAR 0x0000010 /* '$' Dollar sign */ -#define JX9_TK_OP 0x0000020 /* Operator [i.e: +, *, /...] */ -#define JX9_TK_OCB 0x0000040 /* Open curly brace'{' */ -#define JX9_TK_CCB 0x0000080 /* Closing curly brace'}' */ -#define JX9_TK_DOT 0x0000100 /* Dot . */ -#define JX9_TK_LPAREN 0x0000200 /* Left parenthesis '(' */ -#define JX9_TK_RPAREN 0x0000400 /* Right parenthesis ')' */ -#define JX9_TK_OSB 0x0000800 /* Open square bracket '[' */ -#define JX9_TK_CSB 0x0001000 /* Closing square bracket ']' */ -#define JX9_TK_DSTR 0x0002000 /* Double quoted string "$str" */ -#define JX9_TK_SSTR 0x0004000 /* Single quoted string 'str' */ -#define JX9_TK_NOWDOC 0x0010000 /* Nowdoc <<< */ -#define JX9_TK_COMMA 0x0020000 /* Comma ',' */ -#define JX9_TK_SEMI 0x0040000 /* Semi-colon ";" */ -#define JX9_TK_BSTR 0x0080000 /* Backtick quoted string [i.e: Shell command `date`] */ -#define JX9_TK_COLON 0x0100000 /* single Colon ':' */ -#define JX9_TK_AMPER 0x0200000 /* Ampersand '&' */ -#define JX9_TK_EQUAL 0x0400000 /* Equal '=' */ -#define JX9_TK_OTHER 0x1000000 /* Other symbols */ -/* - * JX9 keyword. - * These words have special meaning in JX9. Some of them represent things which look like - * functions, some look like constants, and so on, but they're not, really: they are language constructs. - * You cannot use any of the following words as constants, object names, function or method names. - * Using them as variable names is generally OK, but could lead to confusion. - */ -#define JX9_TKWRD_SWITCH 1 /* switch */ -#define JX9_TKWRD_PRINT 2 /* print */ -#define JX9_TKWRD_ELIF 0x4000000 /* elseif: MUST BE A POWER OF TWO */ -#define JX9_TKWRD_ELSE 0x8000000 /* else: MUST BE A POWER OF TWO */ -#define JX9_TKWRD_IF 3 /* if */ -#define JX9_TKWRD_STATIC 4 /* static */ -#define JX9_TKWRD_CASE 5 /* case */ -#define JX9_TKWRD_FUNCTION 6 /* function */ -#define JX9_TKWRD_CONST 7 /* const */ -/* The number '8' is reserved for JX9_TK_ID */ -#define JX9_TKWRD_WHILE 9 /* while */ -#define JX9_TKWRD_DEFAULT 10 /* default */ -#define JX9_TKWRD_AS 11 /* as */ -#define JX9_TKWRD_CONTINUE 12 /* continue */ -#define JX9_TKWRD_EXIT 13 /* exit */ -#define JX9_TKWRD_DIE 14 /* die */ -#define JX9_TKWRD_IMPORT 15 /* import */ -#define JX9_TKWRD_INCLUDE 16 /* include */ -#define JX9_TKWRD_FOR 17 /* for */ -#define JX9_TKWRD_FOREACH 18 /* foreach */ -#define JX9_TKWRD_RETURN 19 /* return */ -#define JX9_TKWRD_BREAK 20 /* break */ -#define JX9_TKWRD_UPLINK 21 /* uplink */ -#define JX9_TKWRD_BOOL 0x8000 /* bool: MUST BE A POWER OF TWO */ -#define JX9_TKWRD_INT 0x10000 /* int: MUST BE A POWER OF TWO */ -#define JX9_TKWRD_FLOAT 0x20000 /* float: MUST BE A POWER OF TWO */ -#define JX9_TKWRD_STRING 0x40000 /* string: MUST BE A POWER OF TWO */ - -/* api.c */ -JX9_PRIVATE sxi32 jx9EngineConfig(jx9 *pEngine, sxi32 nOp, va_list ap); -JX9_PRIVATE int jx9DeleteFunction(jx9_vm *pVm,const char *zName); -JX9_PRIVATE int Jx9DeleteConstant(jx9_vm *pVm,const char *zName); -/* json.c function prototypes */ -JX9_PRIVATE int jx9JsonSerialize(jx9_value *pValue,SyBlob *pOut); -JX9_PRIVATE int jx9JsonDecode(jx9_context *pCtx,const char *zJSON,int nByte); -/* memobj.c function prototypes */ -JX9_PRIVATE sxi32 jx9MemObjDump(SyBlob *pOut, jx9_value *pObj); -JX9_PRIVATE const char * jx9MemObjTypeDump(jx9_value *pVal); -JX9_PRIVATE sxi32 jx9MemObjAdd(jx9_value *pObj1, jx9_value *pObj2, int bAddStore); -JX9_PRIVATE sxi32 jx9MemObjCmp(jx9_value *pObj1, jx9_value *pObj2, int bStrict, int iNest); -JX9_PRIVATE sxi32 jx9MemObjInitFromString(jx9_vm *pVm, jx9_value *pObj, const SyString *pVal); -JX9_PRIVATE sxi32 jx9MemObjInitFromArray(jx9_vm *pVm, jx9_value *pObj, jx9_hashmap *pArray); -#if 0 -/* Not used in the current release of the JX9 engine */ -JX9_PRIVATE sxi32 jx9MemObjInitFromReal(jx9_vm *pVm, jx9_value *pObj, jx9_real rVal); -#endif -JX9_PRIVATE sxi32 jx9MemObjInitFromInt(jx9_vm *pVm, jx9_value *pObj, sxi64 iVal); -JX9_PRIVATE sxi32 jx9MemObjInitFromBool(jx9_vm *pVm, jx9_value *pObj, sxi32 iVal); -JX9_PRIVATE sxi32 jx9MemObjInit(jx9_vm *pVm, jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjStringAppend(jx9_value *pObj, const char *zData, sxu32 nLen); -#if 0 -/* Not used in the current release of the JX9 engine */ -JX9_PRIVATE sxi32 jx9MemObjStringFormat(jx9_value *pObj, const char *zFormat, va_list ap); -#endif -JX9_PRIVATE sxi32 jx9MemObjStore(jx9_value *pSrc, jx9_value *pDest); -JX9_PRIVATE sxi32 jx9MemObjLoad(jx9_value *pSrc, jx9_value *pDest); -JX9_PRIVATE sxi32 jx9MemObjRelease(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjToNumeric(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjTryInteger(jx9_value *pObj); -JX9_PRIVATE ProcMemObjCast jx9MemObjCastMethod(sxi32 iFlags); -JX9_PRIVATE sxi32 jx9MemObjIsNumeric(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjIsEmpty(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjToHashmap(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjToString(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjToNull(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjToReal(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjToInteger(jx9_value *pObj); -JX9_PRIVATE sxi32 jx9MemObjToBool(jx9_value *pObj); -JX9_PRIVATE sxi64 jx9TokenValueToInt64(SyString *pData); -/* lex.c function prototypes */ -JX9_PRIVATE sxi32 jx9Tokenize(const char *zInput, sxu32 nLen, SySet *pOut); -/* vm.c function prototypes */ -JX9_PRIVATE void jx9VmReleaseContextValue(jx9_context *pCtx, jx9_value *pValue); -JX9_PRIVATE sxi32 jx9VmInitFuncState(jx9_vm *pVm, jx9_vm_func *pFunc, const char *zName, sxu32 nByte, - sxi32 iFlags, void *pUserData); -JX9_PRIVATE sxi32 jx9VmInstallUserFunction(jx9_vm *pVm, jx9_vm_func *pFunc, SyString *pName); -JX9_PRIVATE sxi32 jx9VmRegisterConstant(jx9_vm *pVm, const SyString *pName, ProcConstant xExpand, void *pUserData); -JX9_PRIVATE sxi32 jx9VmInstallForeignFunction(jx9_vm *pVm, const SyString *pName, ProcHostFunction xFunc, void *pUserData); -JX9_PRIVATE sxi32 jx9VmBlobConsumer(const void *pSrc, unsigned int nLen, void *pUserData); -JX9_PRIVATE jx9_value * jx9VmReserveMemObj(jx9_vm *pVm,sxu32 *pIndex); -JX9_PRIVATE jx9_value * jx9VmReserveConstObj(jx9_vm *pVm, sxu32 *pIndex); -JX9_PRIVATE sxi32 jx9VmOutputConsume(jx9_vm *pVm, SyString *pString); -JX9_PRIVATE sxi32 jx9VmOutputConsumeAp(jx9_vm *pVm, const char *zFormat, va_list ap); -JX9_PRIVATE sxi32 jx9VmThrowErrorAp(jx9_vm *pVm, SyString *pFuncName, sxi32 iErr, const char *zFormat, va_list ap); -JX9_PRIVATE sxi32 jx9VmThrowError(jx9_vm *pVm, SyString *pFuncName, sxi32 iErr, const char *zMessage); -JX9_PRIVATE void jx9VmExpandConstantValue(jx9_value *pVal, void *pUserData); -JX9_PRIVATE sxi32 jx9VmDump(jx9_vm *pVm, ProcConsumer xConsumer, void *pUserData); -JX9_PRIVATE sxi32 jx9VmInit(jx9_vm *pVm, jx9 *pEngine); -JX9_PRIVATE sxi32 jx9VmConfigure(jx9_vm *pVm, sxi32 nOp, va_list ap); -JX9_PRIVATE sxi32 jx9VmByteCodeExec(jx9_vm *pVm); -JX9_PRIVATE jx9_value * jx9VmExtractVariable(jx9_vm *pVm,SyString *pVar); -JX9_PRIVATE sxi32 jx9VmRelease(jx9_vm *pVm); -JX9_PRIVATE sxi32 jx9VmReset(jx9_vm *pVm); -JX9_PRIVATE sxi32 jx9VmMakeReady(jx9_vm *pVm); -JX9_PRIVATE sxu32 jx9VmInstrLength(jx9_vm *pVm); -JX9_PRIVATE VmInstr * jx9VmPopInstr(jx9_vm *pVm); -JX9_PRIVATE VmInstr * jx9VmPeekInstr(jx9_vm *pVm); -JX9_PRIVATE VmInstr *jx9VmGetInstr(jx9_vm *pVm, sxu32 nIndex); -JX9_PRIVATE SySet * jx9VmGetByteCodeContainer(jx9_vm *pVm); -JX9_PRIVATE sxi32 jx9VmSetByteCodeContainer(jx9_vm *pVm, SySet *pContainer); -JX9_PRIVATE sxi32 jx9VmEmitInstr(jx9_vm *pVm, sxi32 iOp, sxi32 iP1, sxu32 iP2, void *p3, sxu32 *pIndex); -JX9_PRIVATE sxu32 jx9VmRandomNum(jx9_vm *pVm); -JX9_PRIVATE sxi32 jx9VmCallUserFunction(jx9_vm *pVm, jx9_value *pFunc, int nArg, jx9_value **apArg, jx9_value *pResult); -JX9_PRIVATE sxi32 jx9VmCallUserFunctionAp(jx9_vm *pVm, jx9_value *pFunc, jx9_value *pResult, ...); -JX9_PRIVATE sxi32 jx9VmUnsetMemObj(jx9_vm *pVm, sxu32 nObjIdx); -JX9_PRIVATE void jx9VmRandomString(jx9_vm *pVm, char *zBuf, int nLen); -JX9_PRIVATE int jx9VmIsCallable(jx9_vm *pVm, jx9_value *pValue); -JX9_PRIVATE sxi32 jx9VmPushFilePath(jx9_vm *pVm, const char *zPath, int nLen, sxu8 bMain, sxi32 *pNew); -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE const jx9_io_stream * jx9VmGetStreamDevice(jx9_vm *pVm, const char **pzDevice, int nByte); -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -JX9_PRIVATE int jx9Utf8Read( - const unsigned char *z, /* First byte of UTF-8 character */ - const unsigned char *zTerm, /* Pretend this byte is 0x00 */ - const unsigned char **pzNext /* Write first byte past UTF-8 char here */ -); -/* parse.c function prototypes */ -JX9_PRIVATE int jx9IsLangConstruct(sxu32 nKeyID); -JX9_PRIVATE sxi32 jx9ExprMakeTree(jx9_gen_state *pGen, SySet *pExprNode, jx9_expr_node **ppRoot); -JX9_PRIVATE sxi32 jx9GetNextExpr(SyToken *pStart, SyToken *pEnd, SyToken **ppNext); -JX9_PRIVATE void jx9DelimitNestedTokens(SyToken *pIn, SyToken *pEnd, sxu32 nTokStart, sxu32 nTokEnd, SyToken **ppEnd); -JX9_PRIVATE const jx9_expr_op * jx9ExprExtractOperator(SyString *pStr, SyToken *pLast); -JX9_PRIVATE sxi32 jx9ExprFreeTree(jx9_gen_state *pGen, SySet *pNodeSet); -/* compile.c function prototypes */ -JX9_PRIVATE ProcNodeConstruct jx9GetNodeHandler(sxu32 nNodeType); -JX9_PRIVATE sxi32 jx9CompileLangConstruct(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9CompileJsonArray(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9CompileJsonObject(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9CompileVariable(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9CompileLiteral(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9CompileSimpleString(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9CompileString(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9CompileAnnonFunc(jx9_gen_state *pGen, sxi32 iCompileFlag); -JX9_PRIVATE sxi32 jx9InitCodeGenerator(jx9_vm *pVm, ProcConsumer xErr, void *pErrData); -JX9_PRIVATE sxi32 jx9ResetCodeGenerator(jx9_vm *pVm, ProcConsumer xErr, void *pErrData); -JX9_PRIVATE sxi32 jx9GenCompileError(jx9_gen_state *pGen, sxi32 nErrType, sxu32 nLine, const char *zFormat, ...); -JX9_PRIVATE sxi32 jx9CompileScript(jx9_vm *pVm, SyString *pScript, sxi32 iFlags); -/* constant.c function prototypes */ -JX9_PRIVATE void jx9RegisterBuiltInConstant(jx9_vm *pVm); -/* builtin.c function prototypes */ -JX9_PRIVATE void jx9RegisterBuiltInFunction(jx9_vm *pVm); -/* hashmap.c function prototypes */ -JX9_PRIVATE jx9_hashmap * jx9NewHashmap(jx9_vm *pVm, sxu32 (*xIntHash)(sxi64), sxu32 (*xBlobHash)(const void *, sxu32)); -JX9_PRIVATE sxi32 jx9HashmapLoadBuiltin(jx9_vm *pVm); -JX9_PRIVATE sxi32 jx9HashmapRelease(jx9_hashmap *pMap, int FreeDS); -JX9_PRIVATE void jx9HashmapUnref(jx9_hashmap *pMap); -JX9_PRIVATE sxi32 jx9HashmapLookup(jx9_hashmap *pMap, jx9_value *pKey, jx9_hashmap_node **ppNode); -JX9_PRIVATE sxi32 jx9HashmapInsert(jx9_hashmap *pMap, jx9_value *pKey, jx9_value *pVal); -JX9_PRIVATE sxi32 jx9HashmapUnion(jx9_hashmap *pLeft, jx9_hashmap *pRight); -JX9_PRIVATE sxi32 jx9HashmapDup(jx9_hashmap *pSrc, jx9_hashmap *pDest); -JX9_PRIVATE sxi32 jx9HashmapCmp(jx9_hashmap *pLeft, jx9_hashmap *pRight, int bStrict); -JX9_PRIVATE void jx9HashmapResetLoopCursor(jx9_hashmap *pMap); -JX9_PRIVATE jx9_hashmap_node * jx9HashmapGetNextEntry(jx9_hashmap *pMap); -JX9_PRIVATE jx9_value * jx9HashmapGetNodeValue(jx9_hashmap_node *pNode); -JX9_PRIVATE void jx9HashmapExtractNodeValue(jx9_hashmap_node *pNode, jx9_value *pValue, int bStore); -JX9_PRIVATE void jx9HashmapExtractNodeKey(jx9_hashmap_node *pNode, jx9_value *pKey); -JX9_PRIVATE void jx9RegisterHashmapFunctions(jx9_vm *pVm); -JX9_PRIVATE sxi32 jx9HashmapWalk(jx9_hashmap *pMap, int (*xWalk)(jx9_value *, jx9_value *, void *), void *pUserData); -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE int jx9HashmapValuesToSet(jx9_hashmap *pMap, SySet *pOut); -/* builtin.c function prototypes */ -JX9_PRIVATE sxi32 jx9InputFormat(int (*xConsumer)(jx9_context *, const char *, int, void *), - jx9_context *pCtx, const char *zIn, int nByte, int nArg, jx9_value **apArg, void *pUserData, int vf); -JX9_PRIVATE sxi32 jx9ProcessCsv(const char *zInput, int nByte, int delim, int encl, - int escape, sxi32 (*xConsumer)(const char *, int, void *), void *pUserData); -JX9_PRIVATE sxi32 jx9CsvConsumer(const char *zToken, int nTokenLen, void *pUserData); -JX9_PRIVATE sxi32 jx9StripTagsFromString(jx9_context *pCtx, const char *zIn, int nByte, const char *zTaglist, int nTaglen); -JX9_PRIVATE sxi32 jx9ParseIniString(jx9_context *pCtx, const char *zIn, sxu32 nByte, int bProcessSection); -#endif -/* vfs.c */ -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE void * jx9StreamOpenHandle(jx9_vm *pVm, const jx9_io_stream *pStream, const char *zFile, - int iFlags, int use_include, jx9_value *pResource, int bPushInclude, int *pNew); -JX9_PRIVATE sxi32 jx9StreamReadWholeFile(void *pHandle, const jx9_io_stream *pStream, SyBlob *pOut); -JX9_PRIVATE void jx9StreamCloseHandle(const jx9_io_stream *pStream, void *pHandle); -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -JX9_PRIVATE const char * jx9ExtractDirName(const char *zPath, int nByte, int *pLen); -JX9_PRIVATE sxi32 jx9RegisterIORoutine(jx9_vm *pVm); -JX9_PRIVATE const jx9_vfs * jx9ExportBuiltinVfs(void); -JX9_PRIVATE void * jx9ExportStdin(jx9_vm *pVm); -JX9_PRIVATE void * jx9ExportStdout(jx9_vm *pVm); -JX9_PRIVATE void * jx9ExportStderr(jx9_vm *pVm); -/* lib.c function prototypes */ -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyArchiveInit(SyArchive *pArch, SyMemBackend *pAllocator, ProcHash xHash, ProcRawStrCmp xCmp); -JX9_PRIVATE sxi32 SyArchiveRelease(SyArchive *pArch); -JX9_PRIVATE sxi32 SyArchiveResetLoopCursor(SyArchive *pArch); -JX9_PRIVATE sxi32 SyArchiveGetNextEntry(SyArchive *pArch, SyArchiveEntry **ppEntry); -JX9_PRIVATE sxi32 SyZipExtractFromBuf(SyArchive *pArch, const char *zBuf, sxu32 nLen); -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyBinToHexConsumer(const void *pIn, sxu32 nLen, ProcConsumer xConsumer, void *pConsumerData); -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_HASH_FUNC -JX9_PRIVATE sxu32 SyCrc32(const void *pSrc, sxu32 nLen); -JX9_PRIVATE void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len); -JX9_PRIVATE void MD5Final(unsigned char digest[16], MD5Context *ctx); -JX9_PRIVATE sxi32 MD5Init(MD5Context *pCtx); -JX9_PRIVATE sxi32 SyMD5Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[16]); -JX9_PRIVATE void SHA1Init(SHA1Context *context); -JX9_PRIVATE void SHA1Update(SHA1Context *context, const unsigned char *data, unsigned int len); -JX9_PRIVATE void SHA1Final(SHA1Context *context, unsigned char digest[20]); -JX9_PRIVATE sxi32 SySha1Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[20]); -#endif -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -JX9_PRIVATE sxi32 SyRandomness(SyPRNGCtx *pCtx, void *pBuf, sxu32 nLen); -JX9_PRIVATE sxi32 SyRandomnessInit(SyPRNGCtx *pCtx, ProcRandomSeed xSeed, void *pUserData); -JX9_PRIVATE sxu32 SyBufferFormat(char *zBuf, sxu32 nLen, const char *zFormat, ...); -JX9_PRIVATE sxu32 SyBlobFormatAp(SyBlob *pBlob, const char *zFormat, va_list ap); -JX9_PRIVATE sxu32 SyBlobFormat(SyBlob *pBlob, const char *zFormat, ...); -JX9_PRIVATE sxi32 SyProcFormat(ProcConsumer xConsumer, void *pData, const char *zFormat, ...); -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE const char *SyTimeGetMonth(sxi32 iMonth); -JX9_PRIVATE const char *SyTimeGetDay(sxi32 iDay); -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -JX9_PRIVATE sxi32 SyUriDecode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData, int bUTF8); -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyUriEncode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData); -#endif -JX9_PRIVATE sxi32 SyLexRelease(SyLex *pLex); -JX9_PRIVATE sxi32 SyLexTokenizeInput(SyLex *pLex, const char *zInput, sxu32 nLen, void *pCtxData, ProcSort xSort, ProcCmp xCmp); -JX9_PRIVATE sxi32 SyLexInit(SyLex *pLex, SySet *pSet, ProcTokenizer xTokenizer, void *pUserData); -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyBase64Decode(const char *zB64, sxu32 nLen, ProcConsumer xConsumer, void *pUserData); -JX9_PRIVATE sxi32 SyBase64Encode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData); -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -JX9_PRIVATE sxu32 SyBinHash(const void *pSrc, sxu32 nLen); -JX9_PRIVATE sxi32 SyStrToReal(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest); -JX9_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest); -JX9_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest); -JX9_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest); -JX9_PRIVATE sxi32 SyHexToint(sxi32 c); -JX9_PRIVATE sxi32 SyStrToInt64(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest); -JX9_PRIVATE sxi32 SyStrToInt32(const char *zSrc, sxu32 nLen, void *pOutVal, const char **zRest); -JX9_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc, sxu32 nLen, sxu8 *pReal, const char **pzTail); -JX9_PRIVATE sxi32 SyHashInsert(SyHash *pHash, const void *pKey, sxu32 nKeyLen, void *pUserData); -JX9_PRIVATE sxi32 SyHashForEach(SyHash *pHash, sxi32(*xStep)(SyHashEntry *, void *), void *pUserData); -JX9_PRIVATE sxi32 SyHashDeleteEntry(SyHash *pHash, const void *pKey, sxu32 nKeyLen, void **ppUserData); -JX9_PRIVATE SyHashEntry *SyHashGet(SyHash *pHash, const void *pKey, sxu32 nKeyLen); -JX9_PRIVATE sxi32 SyHashRelease(SyHash *pHash); -JX9_PRIVATE sxi32 SyHashInit(SyHash *pHash, SyMemBackend *pAllocator, ProcHash xHash, ProcCmp xCmp); -JX9_PRIVATE void *SySetAt(SySet *pSet, sxu32 nIdx); -JX9_PRIVATE void *SySetPop(SySet *pSet); -JX9_PRIVATE void *SySetPeek(SySet *pSet); -JX9_PRIVATE sxi32 SySetRelease(SySet *pSet); -JX9_PRIVATE sxi32 SySetReset(SySet *pSet); -JX9_PRIVATE sxi32 SySetResetCursor(SySet *pSet); -JX9_PRIVATE sxi32 SySetGetNextEntry(SySet *pSet, void **ppEntry); -JX9_PRIVATE sxi32 SySetAlloc(SySet *pSet, sxi32 nItem); -JX9_PRIVATE sxi32 SySetPut(SySet *pSet, const void *pItem); -JX9_PRIVATE sxi32 SySetInit(SySet *pSet, SyMemBackend *pAllocator, sxu32 ElemSize); -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyBlobSearch(const void *pBlob, sxu32 nLen, const void *pPattern, sxu32 pLen, sxu32 *pOfft); -#endif -JX9_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob); -JX9_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob); -JX9_PRIVATE sxi32 SyBlobTruncate(SyBlob *pBlob,sxu32 nNewLen); -JX9_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc, SyBlob *pDest); -JX9_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob); -JX9_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob, const void *pData, sxu32 nSize); -JX9_PRIVATE sxi32 SyBlobReadOnly(SyBlob *pBlob, const void *pData, sxu32 nByte); -JX9_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob, SyMemBackend *pAllocator); -JX9_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob, void *pBuffer, sxu32 nSize); -JX9_PRIVATE char *SyMemBackendStrDup(SyMemBackend *pBackend, const char *zSrc, sxu32 nSize); -JX9_PRIVATE void *SyMemBackendDup(SyMemBackend *pBackend, const void *pSrc, sxu32 nSize); -JX9_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend); -JX9_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend, const SyMemMethods *pMethods, ProcMemError xMemErr, void *pUserData); -JX9_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend, ProcMemError xMemErr, void *pUserData); -JX9_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend,const SyMemBackend *pParent); -#if 0 -/* Not used in the current release of the JX9 engine */ -JX9_PRIVATE void *SyMemBackendPoolRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte); -#endif -JX9_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend, void *pChunk); -JX9_PRIVATE void *SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte); -JX9_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend, void *pChunk); -JX9_PRIVATE void *SyMemBackendRealloc(SyMemBackend *pBackend, void *pOld, sxu32 nByte); -JX9_PRIVATE void *SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte); -JX9_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen); -JX9_PRIVATE sxi32 SyMemcmp(const void *pB1, const void *pB2, sxu32 nSize); -JX9_PRIVATE void SyZero(void *pSrc, sxu32 nSize); -JX9_PRIVATE sxi32 SyStrnicmp(const char *zLeft, const char *zRight, sxu32 SLen); -JX9_PRIVATE sxu32 Systrcpy(char *zDest, sxu32 nDestLen, const char *zSrc, sxu32 nLen); -#if !defined(JX9_DISABLE_BUILTIN_FUNC) || defined(__APPLE__) -JX9_PRIVATE sxi32 SyStrncmp(const char *zLeft, const char *zRight, sxu32 nLen); -#endif -JX9_PRIVATE sxi32 SyByteListFind(const char *zSrc, sxu32 nLen, const char *zList, sxu32 *pFirstPos); -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyByteFind2(const char *zStr, sxu32 nLen, sxi32 c, sxu32 *pPos); -#endif -JX9_PRIVATE sxi32 SyByteFind(const char *zStr, sxu32 nLen, sxi32 c, sxu32 *pPos); -JX9_PRIVATE sxu32 SyStrlen(const char *zSrc); -#if defined(JX9_ENABLE_THREADS) -JX9_PRIVATE const SyMutexMethods *SyMutexExportMethods(void); -JX9_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend, const SyMutexMethods *pMethods); -JX9_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend); -#endif -JX9_PRIVATE void SyBigEndianPack32(unsigned char *buf,sxu32 nb); -JX9_PRIVATE void SyBigEndianUnpack32(const unsigned char *buf,sxu32 *uNB); -JX9_PRIVATE void SyBigEndianPack16(unsigned char *buf,sxu16 nb); -JX9_PRIVATE void SyBigEndianUnpack16(const unsigned char *buf,sxu16 *uNB); -JX9_PRIVATE void SyBigEndianPack64(unsigned char *buf,sxu64 n64); -JX9_PRIVATE void SyBigEndianUnpack64(const unsigned char *buf,sxu64 *n64); -JX9_PRIVATE sxi32 SyBlobAppendBig64(SyBlob *pBlob,sxu64 n64); -JX9_PRIVATE sxi32 SyBlobAppendBig32(SyBlob *pBlob,sxu32 n32); -JX9_PRIVATE sxi32 SyBlobAppendBig16(SyBlob *pBlob,sxu16 n16); -JX9_PRIVATE void SyTimeFormatToDos(Sytm *pFmt,sxu32 *pOut); -JX9_PRIVATE void SyDosTimeFormat(sxu32 nDosDate, Sytm *pOut); -#endif /* __JX9INT_H__ */ - -/* - * ---------------------------------------------------------- - * File: unqliteInt.h - * MD5: 325816ce05f6adbaab2c39a41875dedd - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: unqliteInt.h v1.7 FreeBSD 2012-11-02 11:25 devel $ */ -#ifndef __UNQLITEINT_H__ -#define __UNQLITEINT_H__ -/* Internal interface definitions for UnQLite. */ -#ifdef UNQLITE_AMALGAMATION -/* Marker for routines not intended for external use */ -#define UNQLITE_PRIVATE static -#define JX9_AMALGAMATION -#else -#define UNQLITE_PRIVATE -#include "unqlite.h" -#include "jx9Int.h" -#endif -/* forward declaration */ -typedef struct unqlite_db unqlite_db; -/* -** The following values may be passed as the second argument to -** UnqliteOsLock(). The various locks exhibit the following semantics: -** -** SHARED: Any number of processes may hold a SHARED lock simultaneously. -** RESERVED: A single process may hold a RESERVED lock on a file at -** any time. Other processes may hold and obtain new SHARED locks. -** PENDING: A single process may hold a PENDING lock on a file at -** any one time. Existing SHARED locks may persist, but no new -** SHARED locks may be obtained by other processes. -** EXCLUSIVE: An EXCLUSIVE lock precludes all other locks. -** -** PENDING_LOCK may not be passed directly to UnqliteOsLock(). Instead, a -** process that requests an EXCLUSIVE lock may actually obtain a PENDING -** lock. This can be upgraded to an EXCLUSIVE lock by a subsequent call to -** UnqliteOsLock(). -*/ -#define NO_LOCK 0 -#define SHARED_LOCK 1 -#define RESERVED_LOCK 2 -#define PENDING_LOCK 3 -#define EXCLUSIVE_LOCK 4 -/* - * UnQLite Locking Strategy (Same as SQLite3) - * - * The following #defines specify the range of bytes used for locking. - * SHARED_SIZE is the number of bytes available in the pool from which - * a random byte is selected for a shared lock. The pool of bytes for - * shared locks begins at SHARED_FIRST. - * - * The same locking strategy and byte ranges are used for Unix and Windows. - * This leaves open the possiblity of having clients on winNT, and - * unix all talking to the same shared file and all locking correctly. - * To do so would require that samba (or whatever - * tool is being used for file sharing) implements locks correctly between - * windows and unix. I'm guessing that isn't likely to happen, but by - * using the same locking range we are at least open to the possibility. - * - * Locking in windows is mandatory. For this reason, we cannot store - * actual data in the bytes used for locking. The pager never allocates - * the pages involved in locking therefore. SHARED_SIZE is selected so - * that all locks will fit on a single page even at the minimum page size. - * PENDING_BYTE defines the beginning of the locks. By default PENDING_BYTE - * is set high so that we don't have to allocate an unused page except - * for very large databases. But one should test the page skipping logic - * by setting PENDING_BYTE low and running the entire regression suite. - * - * Changing the value of PENDING_BYTE results in a subtly incompatible - * file format. Depending on how it is changed, you might not notice - * the incompatibility right away, even running a full regression test. - * The default location of PENDING_BYTE is the first byte past the - * 1GB boundary. - */ -#define PENDING_BYTE (0x40000000) -#define RESERVED_BYTE (PENDING_BYTE+1) -#define SHARED_FIRST (PENDING_BYTE+2) -#define SHARED_SIZE 510 -/* - * The default size of a disk sector in bytes. - */ -#ifndef UNQLITE_DEFAULT_SECTOR_SIZE -#define UNQLITE_DEFAULT_SECTOR_SIZE 512 -#endif -/* - * Each open database file is managed by a separate instance - * of the "Pager" structure. - */ -typedef struct Pager Pager; -/* - * Each database file to be accessed by the system is an instance - * of the following structure. - */ -struct unqlite_db -{ - Pager *pPager; /* Pager and Transaction manager */ - jx9 *pJx9; /* Jx9 Engine handle */ - unqlite_kv_cursor *pCursor; /* Database cursor for common usage */ -}; -/* - * Each database connection is an instance of the following structure. - */ -struct unqlite -{ - SyMemBackend sMem; /* Memory allocator subsystem */ - SyBlob sErr; /* Error log */ - unqlite_db sDB; /* Storage backend */ -#if defined(UNQLITE_ENABLE_THREADS) - const SyMutexMethods *pMethods; /* Mutex methods */ - SyMutex *pMutex; /* Per-handle mutex */ -#endif - unqlite_vm *pVms; /* List of active VM */ - sxi32 iVm; /* Total number of active VM */ - sxi32 iFlags; /* Control flags (See below) */ - unqlite *pNext,*pPrev; /* List of active DB handles */ - sxu32 nMagic; /* Sanity check against misuse */ -}; -#define UNQLITE_FL_DISABLE_AUTO_COMMIT 0x001 /* Disable auto-commit on close */ -/* - * VM control flags (Mostly related to collection handling). - */ -#define UNQLITE_VM_COLLECTION_CREATE 0x001 /* Create a new collection */ -#define UNQLITE_VM_COLLECTION_EXISTS 0x002 /* Exists old collection */ -#define UNQLITE_VM_AUTO_LOAD 0x004 /* Auto load a collection from the vfs */ -/* Forward declaration */ -typedef struct unqlite_col_record unqlite_col_record; -typedef struct unqlite_col unqlite_col; -/* - * Each an in-memory collection record is stored in an instance - * of the following structure. - */ -struct unqlite_col_record -{ - unqlite_col *pCol; /* Collecion this record belong */ - jx9_int64 nId; /* Unique record ID */ - jx9_value sValue; /* In-memory value of the record */ - unqlite_col_record *pNextCol,*pPrevCol; /* Collision chain */ - unqlite_col_record *pNext,*pPrev; /* Linked list of records */ -}; -/* - * Magic number to identify a valid collection on disk. - */ -#define UNQLITE_COLLECTION_MAGIC 0x611E /* sizeof(unsigned short) 2 bytes */ -/* - * A loaded collection is identified by an instance of the following structure. - */ -struct unqlite_col -{ - unqlite_vm *pVm; /* VM that own this instance */ - SyString sName; /* ID of the collection */ - sxu32 nHash; /* sName hash */ - jx9_value sSchema; /* Collection schema */ - sxu32 nSchemaOfft; /* Shema offset in sHeader */ - SyBlob sWorker; /* General purpose working buffer */ - SyBlob sHeader; /* Collection binary header */ - jx9_int64 nLastid; /* Last collection record ID */ - jx9_int64 nCurid; /* Current record ID */ - jx9_int64 nTotRec; /* Total number of records in the collection */ - int iFlags; /* Control flags (see below) */ - unqlite_col_record **apRecord; /* Hashtable of loaded records */ - unqlite_col_record *pList; /* Linked list of records */ - sxu32 nRec; /* Total number of records in apRecord[] */ - sxu32 nRecSize; /* apRecord[] size */ - Sytm sCreation; /* Colleation creation time */ - unqlite_kv_cursor *pCursor; /* Cursor pointing to the raw binary data */ - unqlite_col *pNext,*pPrev; /* Next and previous collection in the chain */ - unqlite_col *pNextCol,*pPrevCol; /* Collision chain */ -}; -/* - * Each unQLite Virtual Machine resulting from successful compilation of - * a Jx9 script is represented by an instance of the following structure. - */ -struct unqlite_vm -{ - unqlite *pDb; /* Database handle that own this instance */ - SyMemBackend sAlloc; /* Private memory allocator */ -#if defined(UNQLITE_ENABLE_THREADS) - SyMutex *pMutex; /* Recursive mutex associated with this VM. */ -#endif - unqlite_col **apCol; /* Table of loaded collections */ - unqlite_col *pCol; /* List of loaded collections */ - sxu32 iCol; /* Total number of loaded collections */ - sxu32 iColSize; /* apCol[] size */ - jx9_vm *pJx9Vm; /* Compiled Jx9 script*/ - unqlite_vm *pNext,*pPrev; /* Linked list of active unQLite VM */ - sxu32 nMagic; /* Magic number to avoid misuse */ -}; -/* - * Database signature to identify a valid database image. - */ -#define UNQLITE_DB_SIG "unqlite" -/* - * Database magic number (4 bytes). - */ -#define UNQLITE_DB_MAGIC 0xDB7C2712 -/* - * Maximum page size in bytes. - */ -#ifdef UNQLITE_MAX_PAGE_SIZE -# undef UNQLITE_MAX_PAGE_SIZE -#endif -#define UNQLITE_MAX_PAGE_SIZE 65536 /* 65K */ -/* - * Minimum page size in bytes. - */ -#ifdef UNQLITE_MIN_PAGE_SIZE -# undef UNQLITE_MIN_PAGE_SIZE -#endif -#define UNQLITE_MIN_PAGE_SIZE 512 -/* - * The default size of a database page. - */ -#ifndef UNQLITE_DEFAULT_PAGE_SIZE -# undef UNQLITE_DEFAULT_PAGE_SIZE -#endif -# define UNQLITE_DEFAULT_PAGE_SIZE 4096 /* 4K */ -/* Forward declaration */ -typedef struct Bitvec Bitvec; -/* Private library functions */ -/* api.c */ -UNQLITE_PRIVATE const SyMemBackend * unqliteExportMemBackend(void); -UNQLITE_PRIVATE int unqliteDataConsumer( - const void *pOut, /* Data to consume */ - unsigned int nLen, /* Data length */ - void *pUserData /* User private data */ - ); -UNQLITE_PRIVATE unqlite_kv_methods * unqliteFindKVStore( - const char *zName, /* Storage engine name [i.e. Hash, B+tree, LSM, etc.] */ - sxu32 nByte /* zName length */ - ); -UNQLITE_PRIVATE int unqliteGetPageSize(void); -UNQLITE_PRIVATE int unqliteGenError(unqlite *pDb,const char *zErr); -UNQLITE_PRIVATE int unqliteGenErrorFormat(unqlite *pDb,const char *zFmt,...); -UNQLITE_PRIVATE int unqliteGenOutofMem(unqlite *pDb); -/* unql_vm.c */ -UNQLITE_PRIVATE int unqliteExistsCollection(unqlite_vm *pVm, SyString *pName); -UNQLITE_PRIVATE int unqliteCreateCollection(unqlite_vm *pVm,SyString *pName); -UNQLITE_PRIVATE jx9_int64 unqliteCollectionLastRecordId(unqlite_col *pCol); -UNQLITE_PRIVATE jx9_int64 unqliteCollectionCurrentRecordId(unqlite_col *pCol); -UNQLITE_PRIVATE int unqliteCollectionCacheRemoveRecord(unqlite_col *pCol,jx9_int64 nId); -UNQLITE_PRIVATE jx9_int64 unqliteCollectionTotalRecords(unqlite_col *pCol); -UNQLITE_PRIVATE void unqliteCollectionResetRecordCursor(unqlite_col *pCol); -UNQLITE_PRIVATE int unqliteCollectionFetchNextRecord(unqlite_col *pCol,jx9_value *pValue); -UNQLITE_PRIVATE int unqliteCollectionFetchRecordById(unqlite_col *pCol,jx9_int64 nId,jx9_value *pValue); -UNQLITE_PRIVATE unqlite_col * unqliteCollectionFetch(unqlite_vm *pVm,SyString *pCol,int iFlag); -UNQLITE_PRIVATE int unqliteCollectionSetSchema(unqlite_col *pCol,jx9_value *pValue); -UNQLITE_PRIVATE int unqliteCollectionPut(unqlite_col *pCol,jx9_value *pValue,int iFlag); -UNQLITE_PRIVATE int unqliteCollectionDropRecord(unqlite_col *pCol,jx9_int64 nId,int wr_header,int log_err); -UNQLITE_PRIVATE int unqliteDropCollection(unqlite_col *pCol); -/* unql_jx9.c */ -UNQLITE_PRIVATE int unqliteRegisterJx9Functions(unqlite_vm *pVm); -/* fastjson.c */ -UNQLITE_PRIVATE sxi32 FastJsonEncode( - jx9_value *pValue, /* Value to encode */ - SyBlob *pOut, /* Store encoded value here */ - int iNest /* Nesting limit */ - ); -UNQLITE_PRIVATE sxi32 FastJsonDecode( - const void *pIn, /* Binary JSON */ - sxu32 nByte, /* Chunk delimiter */ - jx9_value *pOut, /* Decoded value */ - const unsigned char **pzPtr, - int iNest /* Nesting limit */ - ); -/* vfs.c [io_win.c, io_unix.c ] */ -UNQLITE_PRIVATE const unqlite_vfs * unqliteExportBuiltinVfs(void); -/* mem_kv.c */ -UNQLITE_PRIVATE const unqlite_kv_methods * unqliteExportMemKvStorage(void); -/* lhash_kv.c */ -UNQLITE_PRIVATE const unqlite_kv_methods * unqliteExportDiskKvStorage(void); -/* os.c */ -UNQLITE_PRIVATE int unqliteOsRead(unqlite_file *id, void *pBuf, unqlite_int64 amt, unqlite_int64 offset); -UNQLITE_PRIVATE int unqliteOsWrite(unqlite_file *id, const void *pBuf, unqlite_int64 amt, unqlite_int64 offset); -UNQLITE_PRIVATE int unqliteOsTruncate(unqlite_file *id, unqlite_int64 size); -UNQLITE_PRIVATE int unqliteOsSync(unqlite_file *id, int flags); -UNQLITE_PRIVATE int unqliteOsFileSize(unqlite_file *id, unqlite_int64 *pSize); -UNQLITE_PRIVATE int unqliteOsLock(unqlite_file *id, int lockType); -UNQLITE_PRIVATE int unqliteOsUnlock(unqlite_file *id, int lockType); -UNQLITE_PRIVATE int unqliteOsCheckReservedLock(unqlite_file *id, int *pResOut); -UNQLITE_PRIVATE int unqliteOsSectorSize(unqlite_file *id); -UNQLITE_PRIVATE int unqliteOsOpen( - unqlite_vfs *pVfs, - SyMemBackend *pAlloc, - const char *zPath, - unqlite_file **ppOut, - unsigned int flags -); -UNQLITE_PRIVATE int unqliteOsCloseFree(SyMemBackend *pAlloc,unqlite_file *pId); -UNQLITE_PRIVATE int unqliteOsDelete(unqlite_vfs *pVfs, const char *zPath, int dirSync); -UNQLITE_PRIVATE int unqliteOsAccess(unqlite_vfs *pVfs,const char *zPath,int flags,int *pResOut); -/* bitmap.c */ -UNQLITE_PRIVATE Bitvec *unqliteBitvecCreate(SyMemBackend *pAlloc,pgno iSize); -UNQLITE_PRIVATE int unqliteBitvecTest(Bitvec *p,pgno i); -UNQLITE_PRIVATE int unqliteBitvecSet(Bitvec *p,pgno i); -UNQLITE_PRIVATE void unqliteBitvecDestroy(Bitvec *p); -/* pager.c */ -UNQLITE_PRIVATE int unqliteInitCursor(unqlite *pDb,unqlite_kv_cursor **ppOut); -UNQLITE_PRIVATE int unqliteReleaseCursor(unqlite *pDb,unqlite_kv_cursor *pCur); -UNQLITE_PRIVATE int unqlitePagerSetCachesize(Pager *pPager,int mxPage); -UNQLITE_PRIVATE int unqlitePagerClose(Pager *pPager); -UNQLITE_PRIVATE int unqlitePagerOpen( - unqlite_vfs *pVfs, /* The virtual file system to use */ - unqlite *pDb, /* Database handle */ - const char *zFilename, /* Name of the database file to open */ - unsigned int iFlags /* flags controlling this file */ - ); -UNQLITE_PRIVATE int unqlitePagerRegisterKvEngine(Pager *pPager,unqlite_kv_methods *pMethods); -UNQLITE_PRIVATE unqlite_kv_engine * unqlitePagerGetKvEngine(unqlite *pDb); -UNQLITE_PRIVATE int unqlitePagerBegin(Pager *pPager); -UNQLITE_PRIVATE int unqlitePagerCommit(Pager *pPager); -UNQLITE_PRIVATE int unqlitePagerRollback(Pager *pPager,int bResetKvEngine); -UNQLITE_PRIVATE void unqlitePagerRandomString(Pager *pPager,char *zBuf,sxu32 nLen); -UNQLITE_PRIVATE sxu32 unqlitePagerRandomNum(Pager *pPager); -#endif /* __UNQLITEINT_H__ */ -/* - * ---------------------------------------------------------- - * File: api.c - * MD5: d79e8404e50dacd0ea75635c1ebe553a - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: api.c v2.0 FreeBSD 2012-11-08 23:07 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* This file implement the public interfaces presented to host-applications. - * Routines in other files are for internal use by UnQLite and should not be - * accessed by users of the library. - */ -#define UNQLITE_DB_MISUSE(DB) (DB == 0 || DB->nMagic != UNQLITE_DB_MAGIC) -#define UNQLITE_VM_MISUSE(VM) (VM == 0 || VM->nMagic == JX9_VM_STALE) -/* If another thread have released a working instance, the following macros - * evaluates to true. These macros are only used when the library - * is built with threading support enabled. - */ -#define UNQLITE_THRD_DB_RELEASE(DB) (DB->nMagic != UNQLITE_DB_MAGIC) -#define UNQLITE_THRD_VM_RELEASE(VM) (VM->nMagic == JX9_VM_STALE) -/* IMPLEMENTATION: unqlite@embedded@symisc 118-09-4785 */ -/* - * All global variables are collected in the structure named "sUnqlMPGlobal". - * That way it is clear in the code when we are using static variable because - * its name start with sUnqlMPGlobal. - */ -static struct unqlGlobal_Data -{ - SyMemBackend sAllocator; /* Global low level memory allocator */ -#if defined(UNQLITE_ENABLE_THREADS) - const SyMutexMethods *pMutexMethods; /* Mutex methods */ - SyMutex *pMutex; /* Global mutex */ - sxu32 nThreadingLevel; /* Threading level: 0 == Single threaded/1 == Multi-Threaded - * The threading level can be set using the [unqlite_lib_config()] - * interface with a configuration verb set to - * UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE or - * UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI - */ -#endif - SySet kv_storage; /* Installed KV storage engines */ - int iPageSize; /* Default Page size */ - unqlite_vfs *pVfs; /* Underlying virtual file system (Vfs) */ - sxi32 nDB; /* Total number of active DB handles */ - unqlite *pDB; /* List of active DB handles */ - sxu32 nMagic; /* Sanity check against library misuse */ -}sUnqlMPGlobal = { - {0, 0, 0, 0, 0, 0, 0, 0, {0}}, -#if defined(UNQLITE_ENABLE_THREADS) - 0, - 0, - 0, -#endif - {0, 0, 0, 0, 0, 0, 0 }, - UNQLITE_DEFAULT_PAGE_SIZE, - 0, - 0, - 0, - 0 -}; -#define UNQLITE_LIB_MAGIC 0xEA1495BA -#define UNQLITE_LIB_MISUSE (sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC) -/* - * Supported threading level. - * These options have meaning only when the library is compiled with multi-threading - * support. That is, the UNQLITE_ENABLE_THREADS compile time directive must be defined - * when UnQLite is built. - * UNQLITE_THREAD_LEVEL_SINGLE: - * In this mode, mutexing is disabled and the library can only be used by a single thread. - * UNQLITE_THREAD_LEVEL_MULTI - * In this mode, all mutexes including the recursive mutexes on [unqlite] objects - * are enabled so that the application is free to share the same database handle - * between different threads at the same time. - */ -#define UNQLITE_THREAD_LEVEL_SINGLE 1 -#define UNQLITE_THREAD_LEVEL_MULTI 2 -/* - * Find a Key Value storage engine from the set of installed engines. - * Return a pointer to the storage engine methods on success. NULL on failure. - */ -UNQLITE_PRIVATE unqlite_kv_methods * unqliteFindKVStore( - const char *zName, /* Storage engine name [i.e. Hash, B+tree, LSM, etc.] */ - sxu32 nByte /* zName length */ - ) -{ - unqlite_kv_methods **apStore,*pEntry; - sxu32 n,nMax; - /* Point to the set of installed engines */ - apStore = (unqlite_kv_methods **)SySetBasePtr(&sUnqlMPGlobal.kv_storage); - nMax = SySetUsed(&sUnqlMPGlobal.kv_storage); - for( n = 0 ; n < nMax; ++n ){ - pEntry = apStore[n]; - if( nByte == SyStrlen(pEntry->zName) && SyStrnicmp(pEntry->zName,zName,nByte) == 0 ){ - /* Storage engine found */ - return pEntry; - } - } - /* No such entry, return NULL */ - return 0; -} -/* - * Configure the UnQLite library. - * Return UNQLITE_OK on success. Any other return value indicates failure. - * Refer to [unqlite_lib_config()]. - */ -static sxi32 unqliteCoreConfigure(sxi32 nOp, va_list ap) -{ - int rc = UNQLITE_OK; - switch(nOp){ - case UNQLITE_LIB_CONFIG_PAGE_SIZE: { - /* Default page size: Must be a power of two */ - int iPage = va_arg(ap,int); - if( iPage >= UNQLITE_MIN_PAGE_SIZE && iPage <= UNQLITE_MAX_PAGE_SIZE ){ - if( !(iPage & (iPage - 1)) ){ - sUnqlMPGlobal.iPageSize = iPage; - }else{ - /* Invalid page size */ - rc = UNQLITE_INVALID; - } - }else{ - /* Invalid page size */ - rc = UNQLITE_INVALID; - } - break; - } - case UNQLITE_LIB_CONFIG_STORAGE_ENGINE: { - /* Install a key value storage engine */ - unqlite_kv_methods *pMethods = va_arg(ap,unqlite_kv_methods *); - /* Make sure we are delaing with a valid methods */ - if( pMethods == 0 || SX_EMPTY_STR(pMethods->zName) || pMethods->xSeek == 0 || pMethods->xData == 0 - || pMethods->xKey == 0 || pMethods->xDataLength == 0 || pMethods->xKeyLength == 0 - || pMethods->szKv < (int)sizeof(unqlite_kv_engine) ){ - rc = UNQLITE_INVALID; - break; - } - /* Install it */ - rc = SySetPut(&sUnqlMPGlobal.kv_storage,(const void *)&pMethods); - break; - } - case UNQLITE_LIB_CONFIG_VFS:{ - /* Install a virtual file system */ - unqlite_vfs *pVfs = va_arg(ap,unqlite_vfs *); - if( pVfs ){ - sUnqlMPGlobal.pVfs = pVfs; - } - break; - } - case UNQLITE_LIB_CONFIG_USER_MALLOC: { - /* Use an alternative low-level memory allocation routines */ - const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *); - /* Save the memory failure callback (if available) */ - ProcMemError xMemErr = sUnqlMPGlobal.sAllocator.xMemError; - void *pMemErr = sUnqlMPGlobal.sAllocator.pUserData; - if( pMethods == 0 ){ - /* Use the built-in memory allocation subsystem */ - rc = SyMemBackendInit(&sUnqlMPGlobal.sAllocator, xMemErr, pMemErr); - }else{ - rc = SyMemBackendInitFromOthers(&sUnqlMPGlobal.sAllocator, pMethods, xMemErr, pMemErr); - } - break; - } - case UNQLITE_LIB_CONFIG_MEM_ERR_CALLBACK: { - /* Memory failure callback */ - ProcMemError xMemErr = va_arg(ap, ProcMemError); - void *pUserData = va_arg(ap, void *); - sUnqlMPGlobal.sAllocator.xMemError = xMemErr; - sUnqlMPGlobal.sAllocator.pUserData = pUserData; - break; - } - case UNQLITE_LIB_CONFIG_USER_MUTEX: { -#if defined(UNQLITE_ENABLE_THREADS) - /* Use an alternative low-level mutex subsystem */ - const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *); -#if defined (UNTRUST) - if( pMethods == 0 ){ - rc = UNQLITE_CORRUPT; - } -#endif - /* Sanity check */ - if( pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0){ - /* At least three criticial callbacks xEnter(), xLeave() and xNew() must be supplied */ - rc = UNQLITE_CORRUPT; - break; - } - if( sUnqlMPGlobal.pMutexMethods ){ - /* Overwrite the previous mutex subsystem */ - SyMutexRelease(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); - if( sUnqlMPGlobal.pMutexMethods->xGlobalRelease ){ - sUnqlMPGlobal.pMutexMethods->xGlobalRelease(); - } - sUnqlMPGlobal.pMutex = 0; - } - /* Initialize and install the new mutex subsystem */ - if( pMethods->xGlobalInit ){ - rc = pMethods->xGlobalInit(); - if ( rc != UNQLITE_OK ){ - break; - } - } - /* Create the global mutex */ - sUnqlMPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST); - if( sUnqlMPGlobal.pMutex == 0 ){ - /* - * If the supplied mutex subsystem is so sick that we are unable to - * create a single mutex, there is no much we can do here. - */ - if( pMethods->xGlobalRelease ){ - pMethods->xGlobalRelease(); - } - rc = UNQLITE_CORRUPT; - break; - } - sUnqlMPGlobal.pMutexMethods = pMethods; - if( sUnqlMPGlobal.nThreadingLevel == 0 ){ - /* Set a default threading level */ - sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_MULTI; - } -#endif - break; - } - case UNQLITE_LIB_CONFIG_THREAD_LEVEL_SINGLE: -#if defined(UNQLITE_ENABLE_THREADS) - /* Single thread mode (Only one thread is allowed to play with the library) */ - sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_SINGLE; - jx9_lib_config(JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE); -#endif - break; - case UNQLITE_LIB_CONFIG_THREAD_LEVEL_MULTI: -#if defined(UNQLITE_ENABLE_THREADS) - /* Multi-threading mode (library is thread safe and database handles and virtual machines - * may be shared between multiple threads). - */ - sUnqlMPGlobal.nThreadingLevel = UNQLITE_THREAD_LEVEL_MULTI; - jx9_lib_config(JX9_LIB_CONFIG_THREAD_LEVEL_MULTI); -#endif - break; - default: - /* Unknown configuration option */ - rc = UNQLITE_CORRUPT; - break; - } - return rc; -} -/* - * [CAPIREF: unqlite_lib_config()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_lib_config(int nConfigOp,...) -{ - va_list ap; - int rc; - if( sUnqlMPGlobal.nMagic == UNQLITE_LIB_MAGIC ){ - /* Library is already initialized, this operation is forbidden */ - return UNQLITE_LOCKED; - } - va_start(ap,nConfigOp); - rc = unqliteCoreConfigure(nConfigOp,ap); - va_end(ap); - return rc; -} -/* - * Global library initialization - * Refer to [unqlite_lib_init()] - * This routine must be called to initialize the memory allocation subsystem, the mutex - * subsystem prior to doing any serious work with the library. The first thread to call - * this routine does the initialization process and set the magic number so no body later - * can re-initialize the library. If subsequent threads call this routine before the first - * thread have finished the initialization process, then the subsequent threads must block - * until the initialization process is done. - */ -static sxi32 unqliteCoreInitialize(void) -{ - const unqlite_kv_methods *pMethods; - const unqlite_vfs *pVfs; /* Built-in vfs */ -#if defined(UNQLITE_ENABLE_THREADS) - const SyMutexMethods *pMutexMethods = 0; - SyMutex *pMaster = 0; -#endif - int rc; - /* - * If the library is already initialized, then a call to this routine - * is a no-op. - */ - if( sUnqlMPGlobal.nMagic == UNQLITE_LIB_MAGIC ){ - return UNQLITE_OK; /* Already initialized */ - } - if( sUnqlMPGlobal.pVfs == 0 ){ - /* Point to the built-in vfs */ - pVfs = unqliteExportBuiltinVfs(); - /* Install it */ - unqlite_lib_config(UNQLITE_LIB_CONFIG_VFS, pVfs); - } -#if defined(UNQLITE_ENABLE_THREADS) - if( sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_SINGLE ){ - pMutexMethods = sUnqlMPGlobal.pMutexMethods; - if( pMutexMethods == 0 ){ - /* Use the built-in mutex subsystem */ - pMutexMethods = SyMutexExportMethods(); - if( pMutexMethods == 0 ){ - return UNQLITE_CORRUPT; /* Can't happen */ - } - /* Install the mutex subsystem */ - rc = unqlite_lib_config(UNQLITE_LIB_CONFIG_USER_MUTEX, pMutexMethods); - if( rc != UNQLITE_OK ){ - return rc; - } - } - /* Obtain a static mutex so we can initialize the library without calling malloc() */ - pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1); - if( pMaster == 0 ){ - return UNQLITE_CORRUPT; /* Can't happen */ - } - } - /* Lock the master mutex */ - rc = UNQLITE_OK; - SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ - if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){ -#endif - if( sUnqlMPGlobal.sAllocator.pMethods == 0 ){ - /* Install a memory subsystem */ - rc = unqlite_lib_config(UNQLITE_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */ - if( rc != UNQLITE_OK ){ - /* If we are unable to initialize the memory backend, there is no much we can do here.*/ - goto End; - } - } -#if defined(UNQLITE_ENABLE_THREADS) - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){ - /* Protect the memory allocation subsystem */ - rc = SyMemBackendMakeThreadSafe(&sUnqlMPGlobal.sAllocator, sUnqlMPGlobal.pMutexMethods); - if( rc != UNQLITE_OK ){ - goto End; - } - } -#endif - SySetInit(&sUnqlMPGlobal.kv_storage,&sUnqlMPGlobal.sAllocator,sizeof(unqlite_kv_methods *)); - /* Install the built-in Key Value storage engines */ - pMethods = unqliteExportMemKvStorage(); /* In-memory storage */ - unqlite_lib_config(UNQLITE_LIB_CONFIG_STORAGE_ENGINE,pMethods); - /* Default disk key/value storage engine */ - pMethods = unqliteExportDiskKvStorage(); /* Disk storage */ - unqlite_lib_config(UNQLITE_LIB_CONFIG_STORAGE_ENGINE,pMethods); - /* Default page size */ - if( sUnqlMPGlobal.iPageSize < UNQLITE_MIN_PAGE_SIZE ){ - unqlite_lib_config(UNQLITE_LIB_CONFIG_PAGE_SIZE,UNQLITE_DEFAULT_PAGE_SIZE); - } - /* Our library is initialized, set the magic number */ - sUnqlMPGlobal.nMagic = UNQLITE_LIB_MAGIC; - rc = UNQLITE_OK; -#if defined(UNQLITE_ENABLE_THREADS) - } /* sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC */ -#endif -End: -#if defined(UNQLITE_ENABLE_THREADS) - /* Unlock the master mutex */ - SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ -#endif - return rc; -} -/* Forward declaration */ -static int unqliteVmRelease(unqlite_vm *pVm); -/* - * Release a single instance of an unqlite database handle. - */ -static int unqliteDbRelease(unqlite *pDb) -{ - unqlite_db *pStore = &pDb->sDB; - unqlite_vm *pVm,*pNext; - int rc = UNQLITE_OK; - if( (pDb->iFlags & UNQLITE_FL_DISABLE_AUTO_COMMIT) == 0 ){ - /* Commit any outstanding transaction */ - rc = unqlitePagerCommit(pStore->pPager); - if( rc != UNQLITE_OK ){ - /* Rollback the transaction */ - rc = unqlitePagerRollback(pStore->pPager,FALSE); - } - }else{ - /* Rollback any outstanding transaction */ - rc = unqlitePagerRollback(pStore->pPager,FALSE); - } - /* Close the pager */ - unqlitePagerClose(pStore->pPager); - /* Release any active VM's */ - pVm = pDb->pVms; - for(;;){ - if( pDb->iVm < 1 ){ - break; - } - /* Point to the next entry */ - pNext = pVm->pNext; - unqliteVmRelease(pVm); - pVm = pNext; - pDb->iVm--; - } - /* Release the Jx9 handle */ - jx9_release(pStore->pJx9); - /* Set a dummy magic number */ - pDb->nMagic = 0x7250; - /* Release the whole memory subsystem */ - SyMemBackendRelease(&pDb->sMem); - /* Commit or rollback result */ - return rc; -} -/* - * Release all resources consumed by the library. - * Note: This call is not thread safe. Refer to [unqlite_lib_shutdown()]. - */ -static void unqliteCoreShutdown(void) -{ - unqlite *pDb, *pNext; - /* Release all active databases handles */ - pDb = sUnqlMPGlobal.pDB; - for(;;){ - if( sUnqlMPGlobal.nDB < 1 ){ - break; - } - pNext = pDb->pNext; - unqliteDbRelease(pDb); - pDb = pNext; - sUnqlMPGlobal.nDB--; - } - /* Release the storage methods container */ - SySetRelease(&sUnqlMPGlobal.kv_storage); -#if defined(UNQLITE_ENABLE_THREADS) - /* Release the mutex subsystem */ - if( sUnqlMPGlobal.pMutexMethods ){ - if( sUnqlMPGlobal.pMutex ){ - SyMutexRelease(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); - sUnqlMPGlobal.pMutex = 0; - } - if( sUnqlMPGlobal.pMutexMethods->xGlobalRelease ){ - sUnqlMPGlobal.pMutexMethods->xGlobalRelease(); - } - sUnqlMPGlobal.pMutexMethods = 0; - } - sUnqlMPGlobal.nThreadingLevel = 0; -#endif - if( sUnqlMPGlobal.sAllocator.pMethods ){ - /* Release the memory backend */ - SyMemBackendRelease(&sUnqlMPGlobal.sAllocator); - } - sUnqlMPGlobal.nMagic = 0x1764; - /* Finally, shutdown the Jx9 library */ - jx9_lib_shutdown(); -} -/* - * [CAPIREF: unqlite_lib_init()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_lib_init(void) -{ - int rc; - rc = unqliteCoreInitialize(); - return rc; -} -/* - * [CAPIREF: unqlite_lib_shutdown()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_lib_shutdown(void) -{ - if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){ - /* Already shut */ - return UNQLITE_OK; - } - unqliteCoreShutdown(); - return UNQLITE_OK; -} -/* - * [CAPIREF: unqlite_lib_is_threadsafe()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_lib_is_threadsafe(void) -{ - if( sUnqlMPGlobal.nMagic != UNQLITE_LIB_MAGIC ){ - return 0; - } -#if defined(UNQLITE_ENABLE_THREADS) - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){ - /* Muli-threading support is enabled */ - return 1; - }else{ - /* Single-threading */ - return 0; - } -#else - return 0; -#endif -} -/* - * - * [CAPIREF: unqlite_lib_version()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -const char * unqlite_lib_version(void) -{ - return UNQLITE_VERSION; -} -/* - * - * [CAPIREF: unqlite_lib_signature()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -const char * unqlite_lib_signature(void) -{ - return UNQLITE_SIG; -} -/* - * - * [CAPIREF: unqlite_lib_ident()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -const char * unqlite_lib_ident(void) -{ - return UNQLITE_IDENT; -} -/* - * - * [CAPIREF: unqlite_lib_copyright()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -const char * unqlite_lib_copyright(void) -{ - return UNQLITE_COPYRIGHT; -} -/* - * Remove harmfull and/or stale flags passed to the [unqlite_open()] interface. - */ -static unsigned int unqliteSanityzeFlag(unsigned int iFlags) -{ - iFlags &= ~UNQLITE_OPEN_EXCLUSIVE; /* Reserved flag */ - if( iFlags & UNQLITE_OPEN_TEMP_DB ){ - /* Omit journaling for temporary database */ - iFlags |= UNQLITE_OPEN_OMIT_JOURNALING|UNQLITE_OPEN_CREATE; - } - if( (iFlags & (UNQLITE_OPEN_READONLY|UNQLITE_OPEN_READWRITE)) == 0 ){ - /* Auto-append the R+W flag */ - iFlags |= UNQLITE_OPEN_READWRITE; - } - if( iFlags & UNQLITE_OPEN_CREATE ){ - iFlags &= ~(UNQLITE_OPEN_MMAP|UNQLITE_OPEN_READONLY); - /* Auto-append the R+W flag */ - iFlags |= UNQLITE_OPEN_READWRITE; - }else{ - if( iFlags & UNQLITE_OPEN_READONLY ){ - iFlags &= ~UNQLITE_OPEN_READWRITE; - }else if( iFlags & UNQLITE_OPEN_READWRITE ){ - iFlags &= ~UNQLITE_OPEN_MMAP; - } - } - return iFlags; -} -/* - * This routine does the work of initializing a database handle on behalf - * of [unqlite_open()]. - */ -static int unqliteInitDatabase( - unqlite *pDB, /* Database handle */ - SyMemBackend *pParent, /* Master memory backend */ - const char *zFilename, /* Target database */ - unsigned int iFlags /* Open flags */ - ) -{ - unqlite_db *pStorage = &pDB->sDB; - int rc; - /* Initialiaze the memory subsystem */ - SyMemBackendInitFromParent(&pDB->sMem,pParent); -//#if defined(UNQLITE_ENABLE_THREADS) -// /* No need for internal mutexes */ -// SyMemBackendDisbaleMutexing(&pDB->sMem); -//#endif - SyBlobInit(&pDB->sErr,&pDB->sMem); - /* Sanityze flags */ - iFlags = unqliteSanityzeFlag(iFlags); - /* Init the pager and the transaction manager */ - rc = unqlitePagerOpen(sUnqlMPGlobal.pVfs,pDB,zFilename,iFlags); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Allocate a new Jx9 engine handle */ - rc = jx9_init(&pStorage->pJx9); - if( rc != JX9_OK ){ - return rc; - } - return UNQLITE_OK; -} -/* - * Allocate and initialize a new UnQLite Virtual Mahcine and attach it - * to the compiled Jx9 script. - */ -static int unqliteInitVm(unqlite *pDb,jx9_vm *pJx9Vm,unqlite_vm **ppOut) -{ - unqlite_vm *pVm; - - *ppOut = 0; - /* Allocate a new VM instance */ - pVm = (unqlite_vm *)SyMemBackendPoolAlloc(&pDb->sMem,sizeof(unqlite_vm)); - if( pVm == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pVm,sizeof(unqlite_vm)); - /* Initialize */ - SyMemBackendInitFromParent(&pVm->sAlloc,&pDb->sMem); - /* Allocate a new collection table */ - pVm->apCol = (unqlite_col **)SyMemBackendAlloc(&pVm->sAlloc,32 * sizeof(unqlite_col *)); - if( pVm->apCol == 0 ){ - goto fail; - } - pVm->iColSize = 32; /* Must be a power of two */ - /* Zero the table */ - SyZero((void *)pVm->apCol,pVm->iColSize * sizeof(unqlite_col *)); -#if defined(UNQLITE_ENABLE_THREADS) - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE ){ - /* Associate a recursive mutex with this instance */ - pVm->pMutex = SyMutexNew(sUnqlMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); - if( pVm->pMutex == 0 ){ - goto fail; - } - } -#endif - /* Link the VM to the list of active virtual machines */ - pVm->pJx9Vm = pJx9Vm; - pVm->pDb = pDb; - MACRO_LD_PUSH(pDb->pVms,pVm); - pDb->iVm++; - /* Register Jx9 functions */ - unqliteRegisterJx9Functions(pVm); - /* Set the magic number */ - pVm->nMagic = JX9_VM_INIT; /* Same magic number as Jx9 */ - /* All done */ - *ppOut = pVm; - return UNQLITE_OK; -fail: - SyMemBackendRelease(&pVm->sAlloc); - SyMemBackendPoolFree(&pDb->sMem,pVm); - return UNQLITE_NOMEM; -} -/* - * Release an active VM. - */ -static int unqliteVmRelease(unqlite_vm *pVm) -{ - /* Release the Jx9 VM */ - jx9_vm_release(pVm->pJx9Vm); - /* Release the private memory backend */ - SyMemBackendRelease(&pVm->sAlloc); - /* Upper layer will discard this VM from the list - * of active VM. - */ - return UNQLITE_OK; -} -/* - * Return the default page size. - */ -UNQLITE_PRIVATE int unqliteGetPageSize(void) -{ - int iSize = sUnqlMPGlobal.iPageSize; - if( iSize < UNQLITE_MIN_PAGE_SIZE || iSize > UNQLITE_MAX_PAGE_SIZE ){ - iSize = UNQLITE_DEFAULT_PAGE_SIZE; - } - return iSize; -} -/* - * Generate an error message. - */ -UNQLITE_PRIVATE int unqliteGenError(unqlite *pDb,const char *zErr) -{ - int rc; - /* Append the error message */ - rc = SyBlobAppend(&pDb->sErr,(const void *)zErr,SyStrlen(zErr)); - /* Append a new line */ - SyBlobAppend(&pDb->sErr,(const void *)"\n",sizeof(char)); - return rc; -} -/* - * Generate an error message (Printf like). - */ -UNQLITE_PRIVATE int unqliteGenErrorFormat(unqlite *pDb,const char *zFmt,...) -{ - va_list ap; - int rc; - va_start(ap,zFmt); - rc = SyBlobFormatAp(&pDb->sErr,zFmt,ap); - va_end(ap); - /* Append a new line */ - SyBlobAppend(&pDb->sErr,(const void *)"\n",sizeof(char)); - return rc; -} -/* - * Generate an error message (Out of memory). - */ -UNQLITE_PRIVATE int unqliteGenOutofMem(unqlite *pDb) -{ - int rc; - rc = unqliteGenError(pDb,"unQLite is running out of memory"); - return rc; -} -/* - * Configure a working UnQLite database handle. - */ -static int unqliteConfigure(unqlite *pDb,int nOp,va_list ap) -{ - int rc = UNQLITE_OK; - switch(nOp){ - case UNQLITE_CONFIG_JX9_ERR_LOG: - /* Jx9 compile-time error log */ - rc = jx9EngineConfig(pDb->sDB.pJx9,JX9_CONFIG_ERR_LOG,ap); - break; - case UNQLITE_CONFIG_MAX_PAGE_CACHE: { - int max_page = va_arg(ap,int); - /* Maximum number of page to cache (Simple hint). */ - rc = unqlitePagerSetCachesize(pDb->sDB.pPager,max_page); - break; - } - case UNQLITE_CONFIG_ERR_LOG: { - /* Database error log if any */ - const char **pzPtr = va_arg(ap, const char **); - int *pLen = va_arg(ap, int *); - if( pzPtr == 0 ){ - rc = JX9_CORRUPT; - break; - } - /* NULL terminate the error-log buffer */ - SyBlobNullAppend(&pDb->sErr); - /* Point to the error-log buffer */ - *pzPtr = (const char *)SyBlobData(&pDb->sErr); - if( pLen ){ - if( SyBlobLength(&pDb->sErr) > 1 /* NULL '\0' terminator */ ){ - *pLen = (int)SyBlobLength(&pDb->sErr); - }else{ - *pLen = 0; - } - } - break; - } - case UNQLITE_CONFIG_DISABLE_AUTO_COMMIT:{ - /* Disable auto-commit */ - pDb->iFlags |= UNQLITE_FL_DISABLE_AUTO_COMMIT; - break; - } - case UNQLITE_CONFIG_GET_KV_NAME: { - /* Name of the underlying KV storage engine */ - const char **pzPtr = va_arg(ap,const char **); - if( pzPtr ){ - unqlite_kv_engine *pEngine; - pEngine = unqlitePagerGetKvEngine(pDb); - /* Point to the name */ - *pzPtr = pEngine->pIo->pMethods->zName; - } - break; - } - default: - /* Unknown configuration option */ - rc = UNQLITE_UNKNOWN; - break; - } - return rc; -} -/* - * Export the global (master) memory allocator to submodules. - */ -UNQLITE_PRIVATE const SyMemBackend * unqliteExportMemBackend(void) -{ - return &sUnqlMPGlobal.sAllocator; -} -/* - * [CAPIREF: unqlite_open()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_open(unqlite **ppDB,const char *zFilename,unsigned int iMode) -{ - unqlite *pHandle; - int rc; -#if defined(UNTRUST) - if( ppDB == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - *ppDB = 0; - /* One-time automatic library initialization */ - rc = unqliteCoreInitialize(); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Allocate a new database handle */ - pHandle = (unqlite *)SyMemBackendPoolAlloc(&sUnqlMPGlobal.sAllocator, sizeof(unqlite)); - if( pHandle == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pHandle,sizeof(unqlite)); - if( iMode < 1 ){ - /* Assume a read-only database */ - iMode = UNQLITE_OPEN_READONLY|UNQLITE_OPEN_MMAP; - } - /* Init the database */ - rc = unqliteInitDatabase(pHandle,&sUnqlMPGlobal.sAllocator,zFilename,iMode); - if( rc != UNQLITE_OK ){ - goto Release; - } -#if defined(UNQLITE_ENABLE_THREADS) - if( !(iMode & UNQLITE_OPEN_NOMUTEX) && (sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE) ){ - /* Associate a recursive mutex with this instance */ - pHandle->pMutex = SyMutexNew(sUnqlMPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); - if( pHandle->pMutex == 0 ){ - rc = UNQLITE_NOMEM; - goto Release; - } - } -#endif - /* Link to the list of active DB handles */ -#if defined(UNQLITE_ENABLE_THREADS) - /* Enter the global mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ -#endif - MACRO_LD_PUSH(sUnqlMPGlobal.pDB,pHandle); - sUnqlMPGlobal.nDB++; -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave the global mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ -#endif - /* Set the magic number to identify a valid DB handle */ - pHandle->nMagic = UNQLITE_DB_MAGIC; - /* Make the handle available to the caller */ - *ppDB = pHandle; - return UNQLITE_OK; -Release: - SyMemBackendRelease(&pHandle->sMem); - SyMemBackendPoolFree(&sUnqlMPGlobal.sAllocator,pHandle); - return rc; -} -/* - * [CAPIREF: unqlite_config()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_config(unqlite *pDb,int nConfigOp,...) -{ - va_list ap; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - va_start(ap, nConfigOp); - rc = unqliteConfigure(&(*pDb),nConfigOp, ap); - va_end(ap); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_close()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_close(unqlite *pDb) -{ - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Release the database handle */ - rc = unqliteDbRelease(pDb); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - /* Release DB mutex */ - SyMutexRelease(sUnqlMPGlobal.pMutexMethods, pDb->pMutex) /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif -#if defined(UNQLITE_ENABLE_THREADS) - /* Enter the global mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ -#endif - /* Unlink from the list of active database handles */ - MACRO_LD_REMOVE(sUnqlMPGlobal.pDB, pDb); - sUnqlMPGlobal.nDB--; -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave the global mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods, sUnqlMPGlobal.pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel == UNQLITE_THREAD_LEVEL_SINGLE */ -#endif - /* Release the memory chunk allocated to this handle */ - SyMemBackendPoolFree(&sUnqlMPGlobal.sAllocator,pDb); - return rc; -} -/* - * [CAPIREF: unqlite_compile()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_compile(unqlite *pDb,const char *zJx9,int nByte,unqlite_vm **ppOut) -{ - jx9_vm *pVm; - int rc; - if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; - } -#endif - /* Compile the Jx9 script first */ - rc = jx9_compile(pDb->sDB.pJx9,zJx9,nByte,&pVm); - if( rc == JX9_OK ){ - /* Allocate a new unqlite VM instance */ - rc = unqliteInitVm(pDb,pVm,ppOut); - if( rc != UNQLITE_OK ){ - /* Release the Jx9 VM */ - jx9_vm_release(pVm); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_compile_file()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_compile_file(unqlite *pDb,const char *zPath,unqlite_vm **ppOut) -{ - jx9_vm *pVm; - int rc; - if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; - } -#endif - /* Compile the Jx9 script first */ - rc = jx9_compile_file(pDb->sDB.pJx9,zPath,&pVm); - if( rc == JX9_OK ){ - /* Allocate a new unqlite VM instance */ - rc = unqliteInitVm(pDb,pVm,ppOut); - if( rc != UNQLITE_OK ){ - /* Release the Jx9 VM */ - jx9_vm_release(pVm); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * Configure an unqlite virtual machine (Mostly Jx9 VM) instance. - */ -static int unqliteVmConfig(unqlite_vm *pVm,sxi32 iOp,va_list ap) -{ - int rc; - rc = jx9VmConfigure(pVm->pJx9Vm,iOp,ap); - return rc; -} -/* - * [CAPIREF: unqlite_vm_config()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_vm_config(unqlite_vm *pVm,int iOp,...) -{ - va_list ap; - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - va_start(ap,iOp); - rc = unqliteVmConfig(pVm,iOp,ap); - va_end(ap); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_vm_exec()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_vm_exec(unqlite_vm *pVm) -{ - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Execute the Jx9 bytecode program */ - rc = jx9VmByteCodeExec(pVm->pJx9Vm); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_vm_release()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_vm_release(unqlite_vm *pVm) -{ - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Release the VM */ - rc = unqliteVmRelease(pVm); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave VM mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - /* Release VM mutex */ - SyMutexRelease(sUnqlMPGlobal.pMutexMethods,pVm->pMutex) /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - if( rc == UNQLITE_OK ){ - unqlite *pDb = pVm->pDb; - /* Unlink from the list of active VM's */ -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - MACRO_LD_REMOVE(pDb->pVms, pVm); - pDb->iVm--; - /* Release the memory chunk allocated to this instance */ - SyMemBackendPoolFree(&pDb->sMem,pVm); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - } - return rc; -} -/* - * [CAPIREF: unqlite_vm_reset()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_vm_reset(unqlite_vm *pVm) -{ - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Reset the Jx9 VM */ - rc = jx9VmReset(pVm->pJx9Vm); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_vm_dump()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_vm_dump(unqlite_vm *pVm, int (*xConsumer)(const void *, unsigned int, void *), void *pUserData) -{ - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Dump the Jx9 VM */ - rc = jx9VmDump(pVm->pJx9Vm,xConsumer,pUserData); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_vm_extract_variable()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unqlite_value * unqlite_vm_extract_variable(unqlite_vm *pVm,const char *zVarname) -{ - unqlite_value *pValue; - SyString sVariable; - if( UNQLITE_VM_MISUSE(pVm) ){ - return 0; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return 0; /* Another thread have released this instance */ - } -#endif - /* Extract the target variable */ - SyStringInitFromBuf(&sVariable,zVarname,SyStrlen(zVarname)); - pValue = jx9VmExtractVariable(pVm->pJx9Vm,&sVariable); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return pValue; -} -/* - * [CAPIREF: unqlite_create_function()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_create_function(unqlite_vm *pVm, const char *zName,int (*xFunc)(unqlite_context *,int,unqlite_value **),void *pUserData) -{ - SyString sName; - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } - SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); - /* Remove leading and trailing white spaces */ - SyStringFullTrim(&sName); - /* Ticket 1433-003: NULL values are not allowed */ - if( sName.nByte < 1 || xFunc == 0 ){ - return UNQLITE_INVALID; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Install the foreign function */ - rc = jx9VmInstallForeignFunction(pVm->pJx9Vm,&sName,xFunc,pUserData); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_delete_function()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_delete_function(unqlite_vm *pVm, const char *zName) -{ - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Unlink the foreign function */ - rc = jx9DeleteFunction(pVm->pJx9Vm,zName); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_create_constant()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_create_constant(unqlite_vm *pVm,const char *zName,void (*xExpand)(unqlite_value *, void *),void *pUserData) -{ - SyString sName; - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } - SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); - /* Remove leading and trailing white spaces */ - SyStringFullTrim(&sName); - if( sName.nByte < 1 ){ - /* Empty constant name */ - return UNQLITE_INVALID; - } - /* TICKET 1433-003: NULL pointer is harmless operation */ - if( xExpand == 0 ){ - return UNQLITE_INVALID; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Install the foreign constant */ - rc = jx9VmRegisterConstant(pVm->pJx9Vm,&sName,xExpand,pUserData); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_delete_constant()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_delete_constant(unqlite_vm *pVm, const char *zName) -{ - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Unlink the foreign constant */ - rc = Jx9DeleteConstant(pVm->pJx9Vm,zName); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_value_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_int(unqlite_value *pVal, int iValue) -{ - return jx9_value_int(pVal,iValue); -} -/* - * [CAPIREF: unqlite_value_int64()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_int64(unqlite_value *pVal,unqlite_int64 iValue) -{ - return jx9_value_int64(pVal,iValue); -} -/* - * [CAPIREF: unqlite_value_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_bool(unqlite_value *pVal, int iBool) -{ - return jx9_value_bool(pVal,iBool); -} -/* - * [CAPIREF: unqlite_value_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_null(unqlite_value *pVal) -{ - return jx9_value_null(pVal); -} -/* - * [CAPIREF: unqlite_value_double()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_double(unqlite_value *pVal, double Value) -{ - return jx9_value_double(pVal,Value); -} -/* - * [CAPIREF: unqlite_value_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_string(unqlite_value *pVal, const char *zString, int nLen) -{ - return jx9_value_string(pVal,zString,nLen); -} -/* - * [CAPIREF: unqlite_value_string_format()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_string_format(unqlite_value *pVal, const char *zFormat,...) -{ - va_list ap; - int rc; - if((pVal->iFlags & MEMOBJ_STRING) == 0 ){ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - MemObjSetType(pVal, MEMOBJ_STRING); - } - va_start(ap, zFormat); - rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap); - va_end(ap); - return UNQLITE_OK; -} -/* - * [CAPIREF: unqlite_value_reset_string_cursor()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_reset_string_cursor(unqlite_value *pVal) -{ - return jx9_value_reset_string_cursor(pVal); -} -/* - * [CAPIREF: unqlite_value_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_resource(unqlite_value *pVal,void *pUserData) -{ - return jx9_value_resource(pVal,pUserData); -} -/* - * [CAPIREF: unqlite_value_release()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_release(unqlite_value *pVal) -{ - return jx9_value_release(pVal); -} -/* - * [CAPIREF: unqlite_value_to_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_to_int(unqlite_value *pValue) -{ - return jx9_value_to_int(pValue); -} -/* - * [CAPIREF: unqlite_value_to_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_to_bool(unqlite_value *pValue) -{ - return jx9_value_to_bool(pValue); -} -/* - * [CAPIREF: unqlite_value_to_int64()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unqlite_int64 unqlite_value_to_int64(unqlite_value *pValue) -{ - return jx9_value_to_int64(pValue); -} -/* - * [CAPIREF: unqlite_value_to_double()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -double unqlite_value_to_double(unqlite_value *pValue) -{ - return jx9_value_to_double(pValue); -} -/* - * [CAPIREF: unqlite_value_to_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -const char * unqlite_value_to_string(unqlite_value *pValue, int *pLen) -{ - return jx9_value_to_string(pValue,pLen); -} -/* - * [CAPIREF: unqlite_value_to_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void * unqlite_value_to_resource(unqlite_value *pValue) -{ - return jx9_value_to_resource(pValue); -} -/* - * [CAPIREF: unqlite_value_compare()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_compare(unqlite_value *pLeft, unqlite_value *pRight, int bStrict) -{ - return jx9_value_compare(pLeft,pRight,bStrict); -} -/* - * [CAPIREF: unqlite_result_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_int(unqlite_context *pCtx, int iValue) -{ - return jx9_result_int(pCtx,iValue); -} -/* - * [CAPIREF: unqlite_result_int64()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_int64(unqlite_context *pCtx, unqlite_int64 iValue) -{ - return jx9_result_int64(pCtx,iValue); -} -/* - * [CAPIREF: unqlite_result_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_bool(unqlite_context *pCtx, int iBool) -{ - return jx9_result_bool(pCtx,iBool); -} -/* - * [CAPIREF: unqlite_result_double()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_double(unqlite_context *pCtx, double Value) -{ - return jx9_result_double(pCtx,Value); -} -/* - * [CAPIREF: unqlite_result_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_null(unqlite_context *pCtx) -{ - return jx9_result_null(pCtx); -} -/* - * [CAPIREF: unqlite_result_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_string(unqlite_context *pCtx, const char *zString, int nLen) -{ - return jx9_result_string(pCtx,zString,nLen); -} -/* - * [CAPIREF: unqlite_result_string_format()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_string_format(unqlite_context *pCtx, const char *zFormat, ...) -{ - jx9_value *p; - va_list ap; - int rc; - p = pCtx->pRet; - if( (p->iFlags & MEMOBJ_STRING) == 0 ){ - /* Invalidate any prior representation */ - jx9MemObjRelease(p); - MemObjSetType(p, MEMOBJ_STRING); - } - /* Format the given string */ - va_start(ap, zFormat); - rc = SyBlobFormatAp(&p->sBlob, zFormat, ap); - va_end(ap); - return rc; -} -/* - * [CAPIREF: unqlite_result_value()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_value(unqlite_context *pCtx, unqlite_value *pValue) -{ - return jx9_result_value(pCtx,pValue); -} -/* - * [CAPIREF: unqlite_result_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_result_resource(unqlite_context *pCtx, void *pUserData) -{ - return jx9_result_resource(pCtx,pUserData); -} -/* - * [CAPIREF: unqlite_value_is_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_int(unqlite_value *pVal) -{ - return jx9_value_is_int(pVal); -} -/* - * [CAPIREF: unqlite_value_is_float()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_float(unqlite_value *pVal) -{ - return jx9_value_is_float(pVal); -} -/* - * [CAPIREF: unqlite_value_is_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_bool(unqlite_value *pVal) -{ - return jx9_value_is_bool(pVal); -} -/* - * [CAPIREF: unqlite_value_is_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_string(unqlite_value *pVal) -{ - return jx9_value_is_string(pVal); -} -/* - * [CAPIREF: unqlite_value_is_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_null(unqlite_value *pVal) -{ - return jx9_value_is_null(pVal); -} -/* - * [CAPIREF: unqlite_value_is_numeric()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_numeric(unqlite_value *pVal) -{ - return jx9_value_is_numeric(pVal); -} -/* - * [CAPIREF: unqlite_value_is_callable()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_callable(unqlite_value *pVal) -{ - return jx9_value_is_callable(pVal); -} -/* - * [CAPIREF: unqlite_value_is_scalar()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_scalar(unqlite_value *pVal) -{ - return jx9_value_is_scalar(pVal); -} -/* - * [CAPIREF: unqlite_value_is_json_array()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_json_array(unqlite_value *pVal) -{ - return jx9_value_is_json_array(pVal); -} -/* - * [CAPIREF: unqlite_value_is_json_object()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_json_object(unqlite_value *pVal) -{ - return jx9_value_is_json_object(pVal); -} -/* - * [CAPIREF: unqlite_value_is_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_resource(unqlite_value *pVal) -{ - return jx9_value_is_resource(pVal); -} -/* - * [CAPIREF: unqlite_value_is_empty()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_value_is_empty(unqlite_value *pVal) -{ - return jx9_value_is_empty(pVal); -} -/* - * [CAPIREF: unqlite_array_fetch()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unqlite_value * unqlite_array_fetch(unqlite_value *pArray, const char *zKey, int nByte) -{ - return jx9_array_fetch(pArray,zKey,nByte); -} -/* - * [CAPIREF: unqlite_array_walk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_array_walk(unqlite_value *pArray, int (*xWalk)(unqlite_value *, unqlite_value *, void *), void *pUserData) -{ - return jx9_array_walk(pArray,xWalk,pUserData); -} -/* - * [CAPIREF: unqlite_array_add_elem()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_array_add_elem(unqlite_value *pArray, unqlite_value *pKey, unqlite_value *pValue) -{ - return jx9_array_add_elem(pArray,pKey,pValue); -} -/* - * [CAPIREF: unqlite_array_add_strkey_elem()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_array_add_strkey_elem(unqlite_value *pArray, const char *zKey, unqlite_value *pValue) -{ - return jx9_array_add_strkey_elem(pArray,zKey,pValue); -} -/* - * [CAPIREF: unqlite_array_count()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_array_count(unqlite_value *pArray) -{ - return (int)jx9_array_count(pArray); -} -/* - * [CAPIREF: unqlite_vm_new_scalar()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unqlite_value * unqlite_vm_new_scalar(unqlite_vm *pVm) -{ - unqlite_value *pValue; - if( UNQLITE_VM_MISUSE(pVm) ){ - return 0; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return 0; /* Another thread have released this instance */ - } -#endif - pValue = jx9_new_scalar(pVm->pJx9Vm); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return pValue; -} -/* - * [CAPIREF: unqlite_vm_new_array()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unqlite_value * unqlite_vm_new_array(unqlite_vm *pVm) -{ - unqlite_value *pValue; - if( UNQLITE_VM_MISUSE(pVm) ){ - return 0; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return 0; /* Another thread have released this instance */ - } -#endif - pValue = jx9_new_array(pVm->pJx9Vm); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return pValue; -} -/* - * [CAPIREF: unqlite_vm_release_value()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_vm_release_value(unqlite_vm *pVm,unqlite_value *pValue) -{ - int rc; - if( UNQLITE_VM_MISUSE(pVm) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_VM_RELEASE(pVm) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - rc = jx9_release_value(pVm->pJx9Vm,pValue); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pVm->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_context_output()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_context_output(unqlite_context *pCtx, const char *zString, int nLen) -{ - return jx9_context_output(pCtx,zString,nLen); -} -/* - * [CAPIREF: unqlite_context_output_format()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_context_output_format(unqlite_context *pCtx,const char *zFormat, ...) -{ - va_list ap; - int rc; - va_start(ap, zFormat); - rc = jx9VmOutputConsumeAp(pCtx->pVm,zFormat, ap); - va_end(ap); - return rc; -} -/* - * [CAPIREF: unqlite_context_throw_error()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_context_throw_error(unqlite_context *pCtx, int iErr, const char *zErr) -{ - return jx9_context_throw_error(pCtx,iErr,zErr); -} -/* - * [CAPIREF: unqlite_context_throw_error_format()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_context_throw_error_format(unqlite_context *pCtx, int iErr, const char *zFormat, ...) -{ - va_list ap; - int rc; - if( zFormat == 0){ - return JX9_OK; - } - va_start(ap, zFormat); - rc = jx9VmThrowErrorAp(pCtx->pVm, &pCtx->pFunc->sName, iErr, zFormat, ap); - va_end(ap); - return rc; -} -/* - * [CAPIREF: unqlite_context_random_num()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unsigned int unqlite_context_random_num(unqlite_context *pCtx) -{ - return jx9_context_random_num(pCtx); -} -/* - * [CAPIREF: unqlite_context_random_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_context_random_string(unqlite_context *pCtx, char *zBuf, int nBuflen) -{ - return jx9_context_random_string(pCtx,zBuf,nBuflen); -} -/* - * [CAPIREF: unqlite_context_user_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void * unqlite_context_user_data(unqlite_context *pCtx) -{ - return jx9_context_user_data(pCtx); -} -/* - * [CAPIREF: unqlite_context_push_aux_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_context_push_aux_data(unqlite_context *pCtx, void *pUserData) -{ - return jx9_context_push_aux_data(pCtx,pUserData); -} -/* - * [CAPIREF: unqlite_context_peek_aux_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void * unqlite_context_peek_aux_data(unqlite_context *pCtx) -{ - return jx9_context_peek_aux_data(pCtx); -} -/* - * [CAPIREF: unqlite_context_pop_aux_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void * unqlite_context_pop_aux_data(unqlite_context *pCtx) -{ - return jx9_context_pop_aux_data(pCtx); -} -/* - * [CAPIREF: unqlite_context_result_buf_length()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unsigned int unqlite_context_result_buf_length(unqlite_context *pCtx) -{ - return jx9_context_result_buf_length(pCtx); -} -/* - * [CAPIREF: unqlite_function_name()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -const char * unqlite_function_name(unqlite_context *pCtx) -{ - return jx9_function_name(pCtx); -} -/* - * [CAPIREF: unqlite_context_new_scalar()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unqlite_value * unqlite_context_new_scalar(unqlite_context *pCtx) -{ - return jx9_context_new_scalar(pCtx); -} -/* - * [CAPIREF: unqlite_context_new_array()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -unqlite_value * unqlite_context_new_array(unqlite_context *pCtx) -{ - return jx9_context_new_array(pCtx); -} -/* - * [CAPIREF: unqlite_context_release_value()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void unqlite_context_release_value(unqlite_context *pCtx,unqlite_value *pValue) -{ - jx9_context_release_value(pCtx,pValue); -} -/* - * [CAPIREF: unqlite_context_alloc_chunk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void * unqlite_context_alloc_chunk(unqlite_context *pCtx,unsigned int nByte,int ZeroChunk,int AutoRelease) -{ - return jx9_context_alloc_chunk(pCtx,nByte,ZeroChunk,AutoRelease); -} -/* - * [CAPIREF: unqlite_context_realloc_chunk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void * unqlite_context_realloc_chunk(unqlite_context *pCtx,void *pChunk,unsigned int nByte) -{ - return jx9_context_realloc_chunk(pCtx,pChunk,nByte); -} -/* - * [CAPIREF: unqlite_context_free_chunk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -void unqlite_context_free_chunk(unqlite_context *pCtx,void *pChunk) -{ - jx9_context_free_chunk(pCtx,pChunk); -} -/* - * [CAPIREF: unqlite_kv_store()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_store(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen) -{ - unqlite_kv_engine *pEngine; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - if( pEngine->pIo->pMethods->xReplace == 0 ){ - /* Storage engine does not implement such method */ - unqliteGenError(pDb,"xReplace() method not implemented in the underlying storage engine"); - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - unqliteGenError(pDb,"Empty key"); - rc = UNQLITE_EMPTY; - }else{ - /* Perform the requested operation */ - rc = pEngine->pIo->pMethods->xReplace(pEngine,pKey,nKeyLen,pData,nDataLen); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_store_fmt()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_store_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...) -{ - unqlite_kv_engine *pEngine; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - if( pEngine->pIo->pMethods->xReplace == 0 ){ - /* Storage engine does not implement such method */ - unqliteGenError(pDb,"xReplace() method not implemented in the underlying storage engine"); - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - unqliteGenError(pDb,"Empty key"); - rc = UNQLITE_EMPTY; - }else{ - SyBlob sWorker; /* Working buffer */ - va_list ap; - SyBlobInit(&sWorker,&pDb->sMem); - /* Format the data */ - va_start(ap,zFormat); - SyBlobFormatAp(&sWorker,zFormat,ap); - va_end(ap); - /* Perform the requested operation */ - rc = pEngine->pIo->pMethods->xReplace(pEngine,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker)); - /* Clean up */ - SyBlobRelease(&sWorker); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_append()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_append(unqlite *pDb,const void *pKey,int nKeyLen,const void *pData,unqlite_int64 nDataLen) -{ - unqlite_kv_engine *pEngine; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - if( pEngine->pIo->pMethods->xAppend == 0 ){ - /* Storage engine does not implement such method */ - unqliteGenError(pDb,"xAppend() method not implemented in the underlying storage engine"); - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - unqliteGenError(pDb,"Empty key"); - rc = UNQLITE_EMPTY; - }else{ - /* Perform the requested operation */ - rc = pEngine->pIo->pMethods->xAppend(pEngine,pKey,nKeyLen,pData,nDataLen); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_append_fmt()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_append_fmt(unqlite *pDb,const void *pKey,int nKeyLen,const char *zFormat,...) -{ - unqlite_kv_engine *pEngine; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - if( pEngine->pIo->pMethods->xAppend == 0 ){ - /* Storage engine does not implement such method */ - unqliteGenError(pDb,"xAppend() method not implemented in the underlying storage engine"); - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - unqliteGenError(pDb,"Empty key"); - rc = UNQLITE_EMPTY; - }else{ - SyBlob sWorker; /* Working buffer */ - va_list ap; - SyBlobInit(&sWorker,&pDb->sMem); - /* Format the data */ - va_start(ap,zFormat); - SyBlobFormatAp(&sWorker,zFormat,ap); - va_end(ap); - /* Perform the requested operation */ - rc = pEngine->pIo->pMethods->xAppend(pEngine,pKey,nKeyLen,SyBlobData(&sWorker),SyBlobLength(&sWorker)); - /* Clean up */ - SyBlobRelease(&sWorker); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_fetch()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_fetch(unqlite *pDb,const void *pKey,int nKeyLen,void *pBuf,unqlite_int64 *pBufLen) -{ - unqlite_kv_methods *pMethods; - unqlite_kv_engine *pEngine; - unqlite_kv_cursor *pCur; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - pMethods = pEngine->pIo->pMethods; - pCur = pDb->sDB.pCursor; - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - unqliteGenError(pDb,"Empty key"); - rc = UNQLITE_EMPTY; - }else{ - /* Seek to the record position */ - rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT); - } - if( rc == UNQLITE_OK ){ - if( pBuf == 0 ){ - /* Data length only */ - rc = pMethods->xDataLength(pCur,pBufLen); - }else{ - SyBlob sBlob; - /* Initialize the data consumer */ - SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)*pBufLen); - /* Consume the data */ - rc = pMethods->xData(pCur,unqliteDataConsumer,&sBlob); - /* Data length */ - *pBufLen = (unqlite_int64)SyBlobLength(&sBlob); - /* Cleanup */ - SyBlobRelease(&sBlob); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_fetch_callback()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_fetch_callback(unqlite *pDb,const void *pKey,int nKeyLen,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) -{ - unqlite_kv_methods *pMethods; - unqlite_kv_engine *pEngine; - unqlite_kv_cursor *pCur; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - pMethods = pEngine->pIo->pMethods; - pCur = pDb->sDB.pCursor; - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - unqliteGenError(pDb,"Empty key"); - rc = UNQLITE_EMPTY; - }else{ - /* Seek to the record position */ - rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT); - } - if( rc == UNQLITE_OK && xConsumer ){ - /* Consume the data directly */ - rc = pMethods->xData(pCur,xConsumer,pUserData); - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_delete()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_delete(unqlite *pDb,const void *pKey,int nKeyLen) -{ - unqlite_kv_methods *pMethods; - unqlite_kv_engine *pEngine; - unqlite_kv_cursor *pCur; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - pMethods = pEngine->pIo->pMethods; - pCur = pDb->sDB.pCursor; - if( pMethods->xDelete == 0 ){ - /* Storage engine does not implement such method */ - unqliteGenError(pDb,"xDelete() method not implemented in the underlying storage engine"); - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - unqliteGenError(pDb,"Empty key"); - rc = UNQLITE_EMPTY; - }else{ - /* Seek to the record position */ - rc = pMethods->xSeek(pCur,pKey,nKeyLen,UNQLITE_CURSOR_MATCH_EXACT); - } - if( rc == UNQLITE_OK ){ - /* Exact match found, delete the entry */ - rc = pMethods->xDelete(pCur); - } - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_config()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_config(unqlite *pDb,int iOp,...) -{ - unqlite_kv_engine *pEngine; - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Point to the underlying storage engine */ - pEngine = unqlitePagerGetKvEngine(pDb); - if( pEngine->pIo->pMethods->xConfig == 0 ){ - /* Storage engine does not implements such method */ - unqliteGenError(pDb,"xConfig() method not implemented in the underlying storage engine"); - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - va_list ap; - /* Configure the storage engine */ - va_start(ap,iOp); - rc = pEngine->pIo->pMethods->xConfig(pEngine,iOp,ap); - va_end(ap); - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_init()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_init(unqlite *pDb,unqlite_kv_cursor **ppOut) -{ - int rc; - if( UNQLITE_DB_MISUSE(pDb) || ppOut == 0 /* Noop */){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Allocate a new cursor */ - rc = unqliteInitCursor(pDb,ppOut); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_release()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_release(unqlite *pDb,unqlite_kv_cursor *pCur) -{ - int rc; - if( UNQLITE_DB_MISUSE(pDb) || pCur == 0 /* Noop */){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Release the cursor */ - rc = unqliteReleaseCursor(pDb,pCur); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_first_entry()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_first_entry(unqlite_kv_cursor *pCursor) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Check if the requested method is implemented by the underlying storage engine */ - if( pCursor->pStore->pIo->pMethods->xFirst == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - /* Seek to the first entry */ - rc = pCursor->pStore->pIo->pMethods->xFirst(pCursor); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_last_entry()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_last_entry(unqlite_kv_cursor *pCursor) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Check if the requested method is implemented by the underlying storage engine */ - if( pCursor->pStore->pIo->pMethods->xLast == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - /* Seek to the last entry */ - rc = pCursor->pStore->pIo->pMethods->xLast(pCursor); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_valid_entry()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_valid_entry(unqlite_kv_cursor *pCursor) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Check if the requested method is implemented by the underlying storage engine */ - if( pCursor->pStore->pIo->pMethods->xValid == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - rc = pCursor->pStore->pIo->pMethods->xValid(pCursor); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_next_entry()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_next_entry(unqlite_kv_cursor *pCursor) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Check if the requested method is implemented by the underlying storage engine */ - if( pCursor->pStore->pIo->pMethods->xNext == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - /* Seek to the next entry */ - rc = pCursor->pStore->pIo->pMethods->xNext(pCursor); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_prev_entry()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_prev_entry(unqlite_kv_cursor *pCursor) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Check if the requested method is implemented by the underlying storage engine */ - if( pCursor->pStore->pIo->pMethods->xPrev == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - /* Seek to the previous entry */ - rc = pCursor->pStore->pIo->pMethods->xPrev(pCursor); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_delete_entry()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_delete_entry(unqlite_kv_cursor *pCursor) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Check if the requested method is implemented by the underlying storage engine */ - if( pCursor->pStore->pIo->pMethods->xDelete == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - /* Delete the entry */ - rc = pCursor->pStore->pIo->pMethods->xDelete(pCursor); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_reset()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_reset(unqlite_kv_cursor *pCursor) -{ - int rc = UNQLITE_OK; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Check if the requested method is implemented by the underlying storage engine */ - if( pCursor->pStore->pIo->pMethods->xReset == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - /* Reset */ - pCursor->pStore->pIo->pMethods->xReset(pCursor); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_seek()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_seek(unqlite_kv_cursor *pCursor,const void *pKey,int nKeyLen,int iPos) -{ - int rc = UNQLITE_OK; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - if( nKeyLen < 0 ){ - /* Assume a null terminated string and compute it's length */ - nKeyLen = SyStrlen((const char *)pKey); - } - if( !nKeyLen ){ - rc = UNQLITE_EMPTY; - }else{ - /* Seek to the desired location */ - rc = pCursor->pStore->pIo->pMethods->xSeek(pCursor,pKey,nKeyLen,iPos); - } - return rc; -} -/* - * Default data consumer callback. That is, all retrieved is redirected to this - * routine which store the output in an internal blob. - */ -UNQLITE_PRIVATE int unqliteDataConsumer( - const void *pOut, /* Data to consume */ - unsigned int nLen, /* Data length */ - void *pUserData /* User private data */ - ) -{ - sxi32 rc; - /* Store the output in an internal BLOB */ - rc = SyBlobAppend((SyBlob *)pUserData, pOut, nLen); - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_data_callback()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_key_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Consume the key directly */ - rc = pCursor->pStore->pIo->pMethods->xKey(pCursor,xConsumer,pUserData); - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_key()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_key(unqlite_kv_cursor *pCursor,void *pBuf,int *pnByte) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - if( pBuf == 0 ){ - /* Key length only */ - rc = pCursor->pStore->pIo->pMethods->xKeyLength(pCursor,pnByte); - }else{ - SyBlob sBlob; - if( (*pnByte) < 0 ){ - return UNQLITE_CORRUPT; - } - /* Initialize the data consumer */ - SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)(*pnByte)); - /* Consume the key */ - rc = pCursor->pStore->pIo->pMethods->xKey(pCursor,unqliteDataConsumer,&sBlob); - /* Key length */ - *pnByte = SyBlobLength(&sBlob); - /* Cleanup */ - SyBlobRelease(&sBlob); - } - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_data_callback()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_data_callback(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - /* Consume the data directly */ - rc = pCursor->pStore->pIo->pMethods->xData(pCursor,xConsumer,pUserData); - return rc; -} -/* - * [CAPIREF: unqlite_kv_cursor_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_kv_cursor_data(unqlite_kv_cursor *pCursor,void *pBuf,unqlite_int64 *pnByte) -{ - int rc; -#ifdef UNTRUST - if( pCursor == 0 ){ - return UNQLITE_CORRUPT; - } -#endif - if( pBuf == 0 ){ - /* Data length only */ - rc = pCursor->pStore->pIo->pMethods->xDataLength(pCursor,pnByte); - }else{ - SyBlob sBlob; - if( (*pnByte) < 0 ){ - return UNQLITE_CORRUPT; - } - /* Initialize the data consumer */ - SyBlobInitFromBuf(&sBlob,pBuf,(sxu32)(*pnByte)); - /* Consume the data */ - rc = pCursor->pStore->pIo->pMethods->xData(pCursor,unqliteDataConsumer,&sBlob); - /* Data length */ - *pnByte = SyBlobLength(&sBlob); - /* Cleanup */ - SyBlobRelease(&sBlob); - } - return rc; -} -/* - * [CAPIREF: unqlite_begin()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_begin(unqlite *pDb) -{ - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Begin the write transaction */ - rc = unqlitePagerBegin(pDb->sDB.pPager); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_commit()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_commit(unqlite *pDb) -{ - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Commit the transaction */ - rc = unqlitePagerCommit(pDb->sDB.pPager); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_rollback()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -int unqlite_rollback(unqlite *pDb) -{ - int rc; - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Rollback the transaction */ - rc = unqlitePagerRollback(pDb->sDB.pPager,TRUE); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: unqlite_util_load_mmaped_file()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -UNQLITE_APIEXPORT int unqlite_util_load_mmaped_file(const char *zFile,void **ppMap,unqlite_int64 *pFileSize) -{ - const jx9_vfs *pVfs; - int rc; - if( SX_EMPTY_STR(zFile) || ppMap == 0 || pFileSize == 0){ - /* Sanity check */ - return UNQLITE_CORRUPT; - } - *ppMap = 0; - /* Extract the Jx9 Vfs */ - pVfs = jx9ExportBuiltinVfs(); - /* - * Check if the underlying vfs implement the memory map routines - * [i.e: mmap() under UNIX/MapViewOfFile() under windows]. - */ - if( pVfs == 0 || pVfs->xMmap == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - /* Try to get a read-only memory view of the whole file */ - rc = pVfs->xMmap(zFile,ppMap,pFileSize); - } - return rc; -} -/* - * [CAPIREF: unqlite_util_release_mmaped_file()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -UNQLITE_APIEXPORT int unqlite_util_release_mmaped_file(void *pMap,unqlite_int64 iFileSize) -{ - const jx9_vfs *pVfs; - int rc = UNQLITE_OK; - if( pMap == 0 ){ - return UNQLITE_OK; - } - /* Extract the Jx9 Vfs */ - pVfs = jx9ExportBuiltinVfs(); - if( pVfs == 0 || pVfs->xUnmap == 0 ){ - rc = UNQLITE_NOTIMPLEMENTED; - }else{ - pVfs->xUnmap(pMap,iFileSize); - } - return rc; -} -/* - * [CAPIREF: unqlite_util_random_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -UNQLITE_APIEXPORT int unqlite_util_random_string(unqlite *pDb,char *zBuf,unsigned int buf_size) -{ - if( UNQLITE_DB_MISUSE(pDb) ){ - return UNQLITE_CORRUPT; - } - if( zBuf == 0 || buf_size < 3 ){ - /* Buffer must be long enough to hold three bytes */ - return UNQLITE_INVALID; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return UNQLITE_ABORT; /* Another thread have released this instance */ - } -#endif - /* Generate the random string */ - unqlitePagerRandomString(pDb->sDB.pPager,zBuf,buf_size); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return UNQLITE_OK; -} -/* - * [CAPIREF: unqlite_util_random_num()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -UNQLITE_APIEXPORT unsigned int unqlite_util_random_num(unqlite *pDb) -{ - sxu32 iNum; - if( UNQLITE_DB_MISUSE(pDb) ){ - return 0; - } -#if defined(UNQLITE_ENABLE_THREADS) - /* Acquire DB mutex */ - SyMutexEnter(sUnqlMPGlobal.pMutexMethods, pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ - if( sUnqlMPGlobal.nThreadingLevel > UNQLITE_THREAD_LEVEL_SINGLE && - UNQLITE_THRD_DB_RELEASE(pDb) ){ - return 0; /* Another thread have released this instance */ - } -#endif - /* Generate the random number */ - iNum = unqlitePagerRandomNum(pDb->sDB.pPager); -#if defined(UNQLITE_ENABLE_THREADS) - /* Leave DB mutex */ - SyMutexLeave(sUnqlMPGlobal.pMutexMethods,pDb->pMutex); /* NO-OP if sUnqlMPGlobal.nThreadingLevel != UNQLITE_THREAD_LEVEL_MULTI */ -#endif - return iNum; -} -/* - * ---------------------------------------------------------- - * File: bitvec.c - * MD5: 7e3376710d8454ebcf8c77baacca880f - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: bitvec.c v1.0 Win7 2013-02-27 15:16 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif - -/** This file implements an object that represents a dynmaic -** bitmap. -** -** A bitmap is used to record which pages of a database file have been -** journalled during a transaction, or which pages have the "dont-write" -** property. Usually only a few pages are meet either condition. -** So the bitmap is usually sparse and has low cardinality. -*/ -/* - * Actually, this is not a bitmap but a simple hashtable where page - * number (64-bit unsigned integers) are used as the lookup keys. - */ -typedef struct bitvec_rec bitvec_rec; -struct bitvec_rec -{ - pgno iPage; /* Page number */ - bitvec_rec *pNext,*pNextCol; /* Collison link */ -}; -struct Bitvec -{ - SyMemBackend *pAlloc; /* Memory allocator */ - sxu32 nRec; /* Total number of records */ - sxu32 nSize; /* Table size */ - bitvec_rec **apRec; /* Record table */ - bitvec_rec *pList; /* List of records */ -}; -/* - * Allocate a new bitvec instance. -*/ -UNQLITE_PRIVATE Bitvec * unqliteBitvecCreate(SyMemBackend *pAlloc,pgno iSize) -{ - bitvec_rec **apNew; - Bitvec *p; - - p = (Bitvec *)SyMemBackendAlloc(pAlloc,sizeof(*p) ); - if( p == 0 ){ - SXUNUSED(iSize); /* cc warning */ - return 0; - } - /* Zero the structure */ - SyZero(p,sizeof(Bitvec)); - /* Allocate a new table */ - p->nSize = 64; /* Must be a power of two */ - apNew = (bitvec_rec **)SyMemBackendAlloc(pAlloc,p->nSize * sizeof(bitvec_rec *)); - if( apNew == 0 ){ - SyMemBackendFree(pAlloc,p); - return 0; - } - /* Zero the new table */ - SyZero((void *)apNew,p->nSize * sizeof(bitvec_rec *)); - /* Fill-in */ - p->apRec = apNew; - p->pAlloc = pAlloc; - return p; -} -/* - * Check if the given page number is already installed in the table. - * Return true if installed. False otherwise. - */ -UNQLITE_PRIVATE int unqliteBitvecTest(Bitvec *p,pgno i) -{ - bitvec_rec *pRec; - /* Point to the desired bucket */ - pRec = p->apRec[i & (p->nSize - 1)]; - for(;;){ - if( pRec == 0 ){ break; } - if( pRec->iPage == i ){ - /* Page found */ - return 1; - } - /* Point to the next entry */ - pRec = pRec->pNextCol; - - if( pRec == 0 ){ break; } - if( pRec->iPage == i ){ - /* Page found */ - return 1; - } - /* Point to the next entry */ - pRec = pRec->pNextCol; - - - if( pRec == 0 ){ break; } - if( pRec->iPage == i ){ - /* Page found */ - return 1; - } - /* Point to the next entry */ - pRec = pRec->pNextCol; - - - if( pRec == 0 ){ break; } - if( pRec->iPage == i ){ - /* Page found */ - return 1; - } - /* Point to the next entry */ - pRec = pRec->pNextCol; - } - /* No such entry */ - return 0; -} -/* - * Install a given page number in our bitmap (Actually, our hashtable). - */ -UNQLITE_PRIVATE int unqliteBitvecSet(Bitvec *p,pgno i) -{ - bitvec_rec *pRec; - sxi32 iBuck; - /* Allocate a new instance */ - pRec = (bitvec_rec *)SyMemBackendPoolAlloc(p->pAlloc,sizeof(bitvec_rec)); - if( pRec == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pRec,sizeof(bitvec_rec)); - /* Fill-in */ - pRec->iPage = i; - iBuck = i & (p->nSize - 1); - pRec->pNextCol = p->apRec[iBuck]; - p->apRec[iBuck] = pRec; - pRec->pNext = p->pList; - p->pList = pRec; - p->nRec++; - if( p->nRec >= (p->nSize * 3) && p->nRec < 100000 ){ - /* Grow the hashtable */ - sxu32 nNewSize = p->nSize << 1; - bitvec_rec *pEntry,**apNew; - sxu32 n; - apNew = (bitvec_rec **)SyMemBackendAlloc(p->pAlloc, nNewSize * sizeof(bitvec_rec *)); - if( apNew ){ - sxu32 iBucket; - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(bitvec_rec *)); - /* Rehash all entries */ - n = 0; - pEntry = p->pList; - for(;;){ - /* Loop one */ - if( n >= p->nRec ){ - break; - } - pEntry->pNextCol = 0; - /* Install in the new bucket */ - iBucket = pEntry->iPage & (nNewSize - 1); - pEntry->pNextCol = apNew[iBucket]; - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(p->pAlloc,(void *)p->apRec); - p->apRec = apNew; - p->nSize = nNewSize; - } - } - return UNQLITE_OK; -} -/* - * Destroy a bitvec instance. Reclaim all memory used. - */ -UNQLITE_PRIVATE void unqliteBitvecDestroy(Bitvec *p) -{ - bitvec_rec *pNext,*pRec = p->pList; - SyMemBackend *pAlloc = p->pAlloc; - - for(;;){ - if( p->nRec < 1 ){ - break; - } - pNext = pRec->pNext; - SyMemBackendPoolFree(pAlloc,(void *)pRec); - pRec = pNext; - p->nRec--; - - if( p->nRec < 1 ){ - break; - } - pNext = pRec->pNext; - SyMemBackendPoolFree(pAlloc,(void *)pRec); - pRec = pNext; - p->nRec--; - - - if( p->nRec < 1 ){ - break; - } - pNext = pRec->pNext; - SyMemBackendPoolFree(pAlloc,(void *)pRec); - pRec = pNext; - p->nRec--; - - - if( p->nRec < 1 ){ - break; - } - pNext = pRec->pNext; - SyMemBackendPoolFree(pAlloc,(void *)pRec); - pRec = pNext; - p->nRec--; - } - SyMemBackendFree(pAlloc,(void *)p->apRec); - SyMemBackendFree(pAlloc,p); -} -/* - * ---------------------------------------------------------- - * File: fastjson.c - * MD5: 3693c0022edc7d37b65124d7aef68397 - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: fastjson.c v1.1 FreeBSD 2012-12-05 22:52 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* JSON binary encoding, decoding and stuff like that */ -#ifndef UNQLITE_FAST_JSON_NEST_LIMIT -#if defined(__WINNT__) || defined(__UNIXES__) -#define UNQLITE_FAST_JSON_NEST_LIMIT 64 /* Nesting limit */ -#else -#define UNQLITE_FAST_JSON_NEST_LIMIT 32 /* Nesting limit */ -#endif -#endif /* UNQLITE_FAST_JSON_NEST_LIMIT */ -/* - * JSON to Binary using the FastJSON implementation (BigEndian). - */ -/* - * FastJSON implemented binary token. - */ -#define FJSON_DOC_START 1 /* { */ -#define FJSON_DOC_END 2 /* } */ -#define FJSON_ARRAY_START 3 /* [ */ -#define FJSON_ARRAY_END 4 /* ] */ -#define FJSON_COLON 5 /* : */ -#define FJSON_COMMA 6 /* , */ -#define FJSON_ID 7 /* ID + 4 Bytes length */ -#define FJSON_STRING 8 /* String + 4 bytes length */ -#define FJSON_BYTE 9 /* Byte */ -#define FJSON_INT64 10 /* Integer 64 + 8 bytes */ -#define FJSON_REAL 18 /* Floating point value + 2 bytes */ -#define FJSON_NULL 23 /* NULL */ -#define FJSON_TRUE 24 /* TRUE */ -#define FJSON_FALSE 25 /* FALSE */ -/* - * Encode a Jx9 value to binary JSON. - */ -UNQLITE_PRIVATE sxi32 FastJsonEncode( - jx9_value *pValue, /* Value to encode */ - SyBlob *pOut, /* Store encoded value here */ - int iNest /* Nesting limit */ - ) -{ - sxi32 iType = pValue ? pValue->iFlags : MEMOBJ_NULL; - sxi32 rc = SXRET_OK; - int c; - if( iNest >= UNQLITE_FAST_JSON_NEST_LIMIT ){ - /* Nesting limit reached */ - return SXERR_LIMIT; - } - if( iType & (MEMOBJ_NULL|MEMOBJ_RES) ){ - /* - * Resources are encoded as null also. - */ - c = FJSON_NULL; - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - }else if( iType & MEMOBJ_BOOL ){ - c = pValue->x.iVal ? FJSON_TRUE : FJSON_FALSE; - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - }else if( iType & MEMOBJ_STRING ){ - unsigned char zBuf[sizeof(sxu32)]; /* String length */ - c = FJSON_STRING; - SyBigEndianPack32(zBuf,SyBlobLength(&pValue->sBlob)); - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc == SXRET_OK ){ - rc = SyBlobAppend(pOut,(const void *)zBuf,sizeof(zBuf)); - if( rc == SXRET_OK ){ - rc = SyBlobAppend(pOut,SyBlobData(&pValue->sBlob),SyBlobLength(&pValue->sBlob)); - } - } - }else if( iType & MEMOBJ_INT ){ - unsigned char zBuf[8]; - /* 64bit big endian integer */ - c = FJSON_INT64; - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc == SXRET_OK ){ - SyBigEndianPack64(zBuf,(sxu64)pValue->x.iVal); - rc = SyBlobAppend(pOut,(const void *)zBuf,sizeof(zBuf)); - } - }else if( iType & MEMOBJ_REAL ){ - /* Real number */ - c = FJSON_REAL; - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc == SXRET_OK ){ - sxu32 iOfft = SyBlobLength(pOut); - rc = SyBlobAppendBig16(pOut,0); - if( rc == SXRET_OK ){ - unsigned char *zBlob; - SyBlobFormat(pOut,"%.15g",pValue->x.rVal); - zBlob = (unsigned char *)SyBlobDataAt(pOut,iOfft); - SyBigEndianPack16(zBlob,(sxu16)(SyBlobLength(pOut) - ( 2 + iOfft))); - } - } - }else if( iType & MEMOBJ_HASHMAP ){ - /* A JSON object or array */ - jx9_hashmap *pMap = (jx9_hashmap *)pValue->x.pOther; - jx9_hashmap_node *pNode; - jx9_value *pEntry; - /* Reset the hashmap loop cursor */ - jx9HashmapResetLoopCursor(pMap); - if( pMap->iFlags & HASHMAP_JSON_OBJECT ){ - jx9_value sKey; - /* A JSON object */ - c = FJSON_DOC_START; /* { */ - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc == SXRET_OK ){ - jx9MemObjInit(pMap->pVm,&sKey); - /* Encode object entries */ - while((pNode = jx9HashmapGetNextEntry(pMap)) != 0 ){ - /* Extract the key */ - jx9HashmapExtractNodeKey(pNode,&sKey); - /* Encode it */ - rc = FastJsonEncode(&sKey,pOut,iNest+1); - if( rc != SXRET_OK ){ - break; - } - c = FJSON_COLON; - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc != SXRET_OK ){ - break; - } - /* Extract the value */ - pEntry = jx9HashmapGetNodeValue(pNode); - /* Encode it */ - rc = FastJsonEncode(pEntry,pOut,iNest+1); - if( rc != SXRET_OK ){ - break; - } - /* Delimit the entry */ - c = FJSON_COMMA; - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc != SXRET_OK ){ - break; - } - } - jx9MemObjRelease(&sKey); - if( rc == SXRET_OK ){ - c = FJSON_DOC_END; /* } */ - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - } - } - }else{ - /* A JSON array */ - c = FJSON_ARRAY_START; /* [ */ - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc == SXRET_OK ){ - /* Encode array entries */ - while( (pNode = jx9HashmapGetNextEntry(pMap)) != 0 ){ - /* Extract the value */ - pEntry = jx9HashmapGetNodeValue(pNode); - /* Encode it */ - rc = FastJsonEncode(pEntry,pOut,iNest+1); - if( rc != SXRET_OK ){ - break; - } - /* Delimit the entry */ - c = FJSON_COMMA; - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - if( rc != SXRET_OK ){ - break; - } - } - if( rc == SXRET_OK ){ - c = FJSON_ARRAY_END; /* ] */ - rc = SyBlobAppend(pOut,(const void *)&c,sizeof(char)); - } - } - } - } - return rc; -} -/* - * Decode a FastJSON binary blob. - */ -UNQLITE_PRIVATE sxi32 FastJsonDecode( - const void *pIn, /* Binary JSON */ - sxu32 nByte, /* Chunk delimiter */ - jx9_value *pOut, /* Decoded value */ - const unsigned char **pzPtr, - int iNest /* Nesting limit */ - ) -{ - const unsigned char *zIn = (const unsigned char *)pIn; - const unsigned char *zEnd = &zIn[nByte]; - sxi32 rc = SXRET_OK; - int c; - if( iNest >= UNQLITE_FAST_JSON_NEST_LIMIT ){ - /* Nesting limit reached */ - return SXERR_LIMIT; - } - c = zIn[0]; - /* Advance the stream cursor */ - zIn++; - /* Process the binary token */ - switch(c){ - case FJSON_NULL: - /* null */ - jx9_value_null(pOut); - break; - case FJSON_FALSE: - /* Boolean FALSE */ - jx9_value_bool(pOut,0); - break; - case FJSON_TRUE: - /* Boolean TRUE */ - jx9_value_bool(pOut,1); - break; - case FJSON_INT64: { - /* 64Bit integer */ - sxu64 iVal; - /* Sanity check */ - if( &zIn[8] >= zEnd ){ - /* Corrupt chunk */ - rc = SXERR_CORRUPT; - break; - } - SyBigEndianUnpack64(zIn,&iVal); - /* Advance the pointer */ - zIn += 8; - jx9_value_int64(pOut,(jx9_int64)iVal); - break; - } - case FJSON_REAL: { - /* Real number */ - double iVal = 0; /* cc warning */ - sxu16 iLen; - /* Sanity check */ - if( &zIn[2] >= zEnd ){ - /* Corrupt chunk */ - rc = SXERR_CORRUPT; - break; - } - SyBigEndianUnpack16(zIn,&iLen); - if( &zIn[iLen] >= zEnd ){ - /* Corrupt chunk */ - rc = SXERR_CORRUPT; - break; - } - zIn += 2; - SyStrToReal((const char *)zIn,(sxu32)iLen,&iVal,0); - /* Advance the pointer */ - zIn += iLen; - jx9_value_double(pOut,iVal); - break; - } - case FJSON_STRING: { - /* UTF-8/Binary chunk */ - sxu32 iLength; - /* Sanity check */ - if( &zIn[4] >= zEnd ){ - /* Corrupt chunk */ - rc = SXERR_CORRUPT; - break; - } - SyBigEndianUnpack32(zIn,&iLength); - if( &zIn[iLength] >= zEnd ){ - /* Corrupt chunk */ - rc = SXERR_CORRUPT; - break; - } - zIn += 4; - /* Invalidate any prior representation */ - if( pOut->iFlags & MEMOBJ_STRING ){ - /* Reset the string cursor */ - SyBlobReset(&pOut->sBlob); - } - rc = jx9MemObjStringAppend(pOut,(const char *)zIn,iLength); - /* Update pointer */ - zIn += iLength; - break; - } - case FJSON_ARRAY_START: { - /* Binary JSON array */ - jx9_hashmap *pMap; - jx9_value sVal; - /* Allocate a new hashmap */ - pMap = (jx9_hashmap *)jx9NewHashmap(pOut->pVm,0,0); - if( pMap == 0 ){ - rc = SXERR_MEM; - break; - } - jx9MemObjInit(pOut->pVm,&sVal); - jx9MemObjRelease(pOut); - MemObjSetType(pOut,MEMOBJ_HASHMAP); - pOut->x.pOther = pMap; - rc = SXRET_OK; - for(;;){ - /* Jump leading binary commas */ - while (zIn < zEnd && zIn[0] == FJSON_COMMA ){ - zIn++; - } - if( zIn >= zEnd || zIn[0] == FJSON_ARRAY_END ){ - if( zIn < zEnd ){ - zIn++; /* Jump the trailing binary ] */ - } - break; - } - /* Decode the value */ - rc = FastJsonDecode((const void *)zIn,(sxu32)(zEnd-zIn),&sVal,&zIn,iNest+1); - if( rc != SXRET_OK ){ - break; - } - /* Insert the decoded value */ - rc = jx9HashmapInsert(pMap,0,&sVal); - if( rc != UNQLITE_OK ){ - break; - } - } - if( rc != SXRET_OK ){ - jx9MemObjRelease(pOut); - } - jx9MemObjRelease(&sVal); - break; - } - case FJSON_DOC_START: { - /* Binary JSON object */ - jx9_value sVal,sKey; - jx9_hashmap *pMap; - /* Allocate a new hashmap */ - pMap = (jx9_hashmap *)jx9NewHashmap(pOut->pVm,0,0); - if( pMap == 0 ){ - rc = SXERR_MEM; - break; - } - jx9MemObjInit(pOut->pVm,&sVal); - jx9MemObjInit(pOut->pVm,&sKey); - jx9MemObjRelease(pOut); - MemObjSetType(pOut,MEMOBJ_HASHMAP); - pOut->x.pOther = pMap; - rc = SXRET_OK; - for(;;){ - /* Jump leading binary commas */ - while (zIn < zEnd && zIn[0] == FJSON_COMMA ){ - zIn++; - } - if( zIn >= zEnd || zIn[0] == FJSON_DOC_END ){ - if( zIn < zEnd ){ - zIn++; /* Jump the trailing binary } */ - } - break; - } - /* Extract the key */ - rc = FastJsonDecode((const void *)zIn,(sxu32)(zEnd-zIn),&sKey,&zIn,iNest+1); - if( rc != UNQLITE_OK ){ - break; - } - if( zIn >= zEnd || zIn[0] != FJSON_COLON ){ - rc = UNQLITE_CORRUPT; - break; - } - zIn++; /* Jump the binary colon ':' */ - if( zIn >= zEnd ){ - rc = UNQLITE_CORRUPT; - break; - } - /* Decode the value */ - rc = FastJsonDecode((const void *)zIn,(sxu32)(zEnd-zIn),&sVal,&zIn,iNest+1); - if( rc != SXRET_OK ){ - break; - } - /* Insert the key and its associated value */ - rc = jx9HashmapInsert(pMap,&sKey,&sVal); - if( rc != UNQLITE_OK ){ - break; - } - } - if( rc != SXRET_OK ){ - jx9MemObjRelease(pOut); - } - jx9MemObjRelease(&sVal); - jx9MemObjRelease(&sKey); - break; - } - default: - /* Corrupt data */ - rc = SXERR_CORRUPT; - break; - } - if( pzPtr ){ - *pzPtr = zIn; - } - return rc; -} -/* - * ---------------------------------------------------------- - * File: jx9_api.c - * MD5: 73cba599c009cee0ff878666d0543438 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: api.c v1.7 FreeBSD 2012-12-18 06:54 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* This file implement the public interfaces presented to host-applications. - * Routines in other files are for internal use by JX9 and should not be - * accessed by users of the library. - */ -#define JX9_ENGINE_MAGIC 0xF874BCD7 -#define JX9_ENGINE_MISUSE(ENGINE) (ENGINE == 0 || ENGINE->nMagic != JX9_ENGINE_MAGIC) -#define JX9_VM_MISUSE(VM) (VM == 0 || VM->nMagic == JX9_VM_STALE) -/* If another thread have released a working instance, the following macros - * evaluates to true. These macros are only used when the library - * is built with threading support enabled which is not the case in - * the default built. - */ -#define JX9_THRD_ENGINE_RELEASE(ENGINE) (ENGINE->nMagic != JX9_ENGINE_MAGIC) -#define JX9_THRD_VM_RELEASE(VM) (VM->nMagic == JX9_VM_STALE) -/* IMPLEMENTATION: jx9@embedded@symisc 311-12-32 */ -/* - * All global variables are collected in the structure named "sJx9MPGlobal". - * That way it is clear in the code when we are using static variable because - * its name start with sJx9MPGlobal. - */ -static struct Jx9Global_Data -{ - SyMemBackend sAllocator; /* Global low level memory allocator */ -#if defined(JX9_ENABLE_THREADS) - const SyMutexMethods *pMutexMethods; /* Mutex methods */ - SyMutex *pMutex; /* Global mutex */ - sxu32 nThreadingLevel; /* Threading level: 0 == Single threaded/1 == Multi-Threaded - * The threading level can be set using the [jx9_lib_config()] - * interface with a configuration verb set to - * JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE or - * JX9_LIB_CONFIG_THREAD_LEVEL_MULTI - */ -#endif - const jx9_vfs *pVfs; /* Underlying virtual file system */ - sxi32 nEngine; /* Total number of active engines */ - jx9 *pEngines; /* List of active engine */ - sxu32 nMagic; /* Sanity check against library misuse */ -}sJx9MPGlobal = { - {0, 0, 0, 0, 0, 0, 0, 0, {0}}, -#if defined(JX9_ENABLE_THREADS) - 0, - 0, - 0, -#endif - 0, - 0, - 0, - 0 -}; -#define JX9_LIB_MAGIC 0xEA1495BA -#define JX9_LIB_MISUSE (sJx9MPGlobal.nMagic != JX9_LIB_MAGIC) -/* - * Supported threading level. - * These options have meaning only when the library is compiled with multi-threading - * support.That is, the JX9_ENABLE_THREADS compile time directive must be defined - * when JX9 is built. - * JX9_THREAD_LEVEL_SINGLE: - * In this mode, mutexing is disabled and the library can only be used by a single thread. - * JX9_THREAD_LEVEL_MULTI - * In this mode, all mutexes including the recursive mutexes on [jx9] objects - * are enabled so that the application is free to share the same engine - * between different threads at the same time. - */ -#define JX9_THREAD_LEVEL_SINGLE 1 -#define JX9_THREAD_LEVEL_MULTI 2 -/* - * Configure a running JX9 engine instance. - * return JX9_OK on success.Any other return - * value indicates failure. - * Refer to [jx9_config()]. - */ -JX9_PRIVATE sxi32 jx9EngineConfig(jx9 *pEngine, sxi32 nOp, va_list ap) -{ - jx9_conf *pConf = &pEngine->xConf; - int rc = JX9_OK; - /* Perform the requested operation */ - switch(nOp){ - case JX9_CONFIG_ERR_LOG:{ - /* Extract compile-time error log if any */ - const char **pzPtr = va_arg(ap, const char **); - int *pLen = va_arg(ap, int *); - if( pzPtr == 0 ){ - rc = JX9_CORRUPT; - break; - } - /* NULL terminate the error-log buffer */ - SyBlobNullAppend(&pConf->sErrConsumer); - /* Point to the error-log buffer */ - *pzPtr = (const char *)SyBlobData(&pConf->sErrConsumer); - if( pLen ){ - if( SyBlobLength(&pConf->sErrConsumer) > 1 /* NULL '\0' terminator */ ){ - *pLen = (int)SyBlobLength(&pConf->sErrConsumer); - }else{ - *pLen = 0; - } - } - break; - } - case JX9_CONFIG_ERR_ABORT: - /* Reserved for future use */ - break; - default: - /* Unknown configuration verb */ - rc = JX9_CORRUPT; - break; - } /* Switch() */ - return rc; -} -/* - * Configure the JX9 library. - * Return JX9_OK on success. Any other return value indicates failure. - * Refer to [jx9_lib_config()]. - */ -static sxi32 Jx9CoreConfigure(sxi32 nOp, va_list ap) -{ - int rc = JX9_OK; - switch(nOp){ - case JX9_LIB_CONFIG_VFS:{ - /* Install a virtual file system */ - const jx9_vfs *pVfs = va_arg(ap, const jx9_vfs *); - sJx9MPGlobal.pVfs = pVfs; - break; - } - case JX9_LIB_CONFIG_USER_MALLOC: { - /* Use an alternative low-level memory allocation routines */ - const SyMemMethods *pMethods = va_arg(ap, const SyMemMethods *); - /* Save the memory failure callback (if available) */ - ProcMemError xMemErr = sJx9MPGlobal.sAllocator.xMemError; - void *pMemErr = sJx9MPGlobal.sAllocator.pUserData; - if( pMethods == 0 ){ - /* Use the built-in memory allocation subsystem */ - rc = SyMemBackendInit(&sJx9MPGlobal.sAllocator, xMemErr, pMemErr); - }else{ - rc = SyMemBackendInitFromOthers(&sJx9MPGlobal.sAllocator, pMethods, xMemErr, pMemErr); - } - break; - } - case JX9_LIB_CONFIG_MEM_ERR_CALLBACK: { - /* Memory failure callback */ - ProcMemError xMemErr = va_arg(ap, ProcMemError); - void *pUserData = va_arg(ap, void *); - sJx9MPGlobal.sAllocator.xMemError = xMemErr; - sJx9MPGlobal.sAllocator.pUserData = pUserData; - break; - } - case JX9_LIB_CONFIG_USER_MUTEX: { -#if defined(JX9_ENABLE_THREADS) - /* Use an alternative low-level mutex subsystem */ - const SyMutexMethods *pMethods = va_arg(ap, const SyMutexMethods *); -#if defined (UNTRUST) - if( pMethods == 0 ){ - rc = JX9_CORRUPT; - } -#endif - /* Sanity check */ - if( pMethods->xEnter == 0 || pMethods->xLeave == 0 || pMethods->xNew == 0){ - /* At least three criticial callbacks xEnter(), xLeave() and xNew() must be supplied */ - rc = JX9_CORRUPT; - break; - } - if( sJx9MPGlobal.pMutexMethods ){ - /* Overwrite the previous mutex subsystem */ - SyMutexRelease(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); - if( sJx9MPGlobal.pMutexMethods->xGlobalRelease ){ - sJx9MPGlobal.pMutexMethods->xGlobalRelease(); - } - sJx9MPGlobal.pMutex = 0; - } - /* Initialize and install the new mutex subsystem */ - if( pMethods->xGlobalInit ){ - rc = pMethods->xGlobalInit(); - if ( rc != JX9_OK ){ - break; - } - } - /* Create the global mutex */ - sJx9MPGlobal.pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST); - if( sJx9MPGlobal.pMutex == 0 ){ - /* - * If the supplied mutex subsystem is so sick that we are unable to - * create a single mutex, there is no much we can do here. - */ - if( pMethods->xGlobalRelease ){ - pMethods->xGlobalRelease(); - } - rc = JX9_CORRUPT; - break; - } - sJx9MPGlobal.pMutexMethods = pMethods; - if( sJx9MPGlobal.nThreadingLevel == 0 ){ - /* Set a default threading level */ - sJx9MPGlobal.nThreadingLevel = JX9_THREAD_LEVEL_MULTI; - } -#endif - break; - } - case JX9_LIB_CONFIG_THREAD_LEVEL_SINGLE: -#if defined(JX9_ENABLE_THREADS) - /* Single thread mode(Only one thread is allowed to play with the library) */ - sJx9MPGlobal.nThreadingLevel = JX9_THREAD_LEVEL_SINGLE; -#endif - break; - case JX9_LIB_CONFIG_THREAD_LEVEL_MULTI: -#if defined(JX9_ENABLE_THREADS) - /* Multi-threading mode (library is thread safe and JX9 engines and virtual machines - * may be shared between multiple threads). - */ - sJx9MPGlobal.nThreadingLevel = JX9_THREAD_LEVEL_MULTI; -#endif - break; - default: - /* Unknown configuration option */ - rc = JX9_CORRUPT; - break; - } - return rc; -} -/* - * [CAPIREF: jx9_lib_config()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_lib_config(int nConfigOp, ...) -{ - va_list ap; - int rc; - if( sJx9MPGlobal.nMagic == JX9_LIB_MAGIC ){ - /* Library is already initialized, this operation is forbidden */ - return JX9_LOOKED; - } - va_start(ap, nConfigOp); - rc = Jx9CoreConfigure(nConfigOp, ap); - va_end(ap); - return rc; -} -/* - * Global library initialization - * Refer to [jx9_lib_init()] - * This routine must be called to initialize the memory allocation subsystem, the mutex - * subsystem prior to doing any serious work with the library.The first thread to call - * this routine does the initialization process and set the magic number so no body later - * can re-initialize the library.If subsequent threads call this routine before the first - * thread have finished the initialization process, then the subsequent threads must block - * until the initialization process is done. - */ -static sxi32 Jx9CoreInitialize(void) -{ - const jx9_vfs *pVfs; /* Built-in vfs */ -#if defined(JX9_ENABLE_THREADS) - const SyMutexMethods *pMutexMethods = 0; - SyMutex *pMaster = 0; -#endif - int rc; - /* - * If the library is already initialized, then a call to this routine - * is a no-op. - */ - if( sJx9MPGlobal.nMagic == JX9_LIB_MAGIC ){ - return JX9_OK; /* Already initialized */ - } - if( sJx9MPGlobal.pVfs == 0 ){ - /* Point to the built-in vfs */ - pVfs = jx9ExportBuiltinVfs(); - /* Install it */ - jx9_lib_config(JX9_LIB_CONFIG_VFS, pVfs); - } -#if defined(JX9_ENABLE_THREADS) - if( sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_SINGLE ){ - pMutexMethods = sJx9MPGlobal.pMutexMethods; - if( pMutexMethods == 0 ){ - /* Use the built-in mutex subsystem */ - pMutexMethods = SyMutexExportMethods(); - if( pMutexMethods == 0 ){ - return JX9_CORRUPT; /* Can't happen */ - } - /* Install the mutex subsystem */ - rc = jx9_lib_config(JX9_LIB_CONFIG_USER_MUTEX, pMutexMethods); - if( rc != JX9_OK ){ - return rc; - } - } - /* Obtain a static mutex so we can initialize the library without calling malloc() */ - pMaster = SyMutexNew(pMutexMethods, SXMUTEX_TYPE_STATIC_1); - if( pMaster == 0 ){ - return JX9_CORRUPT; /* Can't happen */ - } - } - /* Lock the master mutex */ - rc = JX9_OK; - SyMutexEnter(pMutexMethods, pMaster); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ - if( sJx9MPGlobal.nMagic != JX9_LIB_MAGIC ){ -#endif - if( sJx9MPGlobal.sAllocator.pMethods == 0 ){ - /* Install a memory subsystem */ - rc = jx9_lib_config(JX9_LIB_CONFIG_USER_MALLOC, 0); /* zero mean use the built-in memory backend */ - if( rc != JX9_OK ){ - /* If we are unable to initialize the memory backend, there is no much we can do here.*/ - goto End; - } - } -#if defined(JX9_ENABLE_THREADS) - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE ){ - /* Protect the memory allocation subsystem */ - rc = SyMemBackendMakeThreadSafe(&sJx9MPGlobal.sAllocator, sJx9MPGlobal.pMutexMethods); - if( rc != JX9_OK ){ - goto End; - } - } -#endif - /* Our library is initialized, set the magic number */ - sJx9MPGlobal.nMagic = JX9_LIB_MAGIC; - rc = JX9_OK; -#if defined(JX9_ENABLE_THREADS) - } /* sJx9MPGlobal.nMagic != JX9_LIB_MAGIC */ -#endif -End: -#if defined(JX9_ENABLE_THREADS) - /* Unlock the master mutex */ - SyMutexLeave(pMutexMethods, pMaster); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ -#endif - return rc; -} -/* - * Release an active JX9 engine and it's associated active virtual machines. - */ -static sxi32 EngineRelease(jx9 *pEngine) -{ - jx9_vm *pVm, *pNext; - /* Release all active VM */ - pVm = pEngine->pVms; - for(;;){ - if( pEngine->iVm < 1 ){ - break; - } - pNext = pVm->pNext; - jx9VmRelease(pVm); - pVm = pNext; - pEngine->iVm--; - } - /* Set a dummy magic number */ - pEngine->nMagic = 0x7635; - /* Release the private memory subsystem */ - SyMemBackendRelease(&pEngine->sAllocator); - return JX9_OK; -} -/* - * Release all resources consumed by the library. - * If JX9 is already shut when this routine is invoked then this - * routine is a harmless no-op. - * Note: This call is not thread safe. Refer to [jx9_lib_shutdown()]. - */ -static void JX9CoreShutdown(void) -{ - jx9 *pEngine, *pNext; - /* Release all active engines first */ - pEngine = sJx9MPGlobal.pEngines; - for(;;){ - if( sJx9MPGlobal.nEngine < 1 ){ - break; - } - pNext = pEngine->pNext; - EngineRelease(pEngine); - pEngine = pNext; - sJx9MPGlobal.nEngine--; - } -#if defined(JX9_ENABLE_THREADS) - /* Release the mutex subsystem */ - if( sJx9MPGlobal.pMutexMethods ){ - if( sJx9MPGlobal.pMutex ){ - SyMutexRelease(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); - sJx9MPGlobal.pMutex = 0; - } - if( sJx9MPGlobal.pMutexMethods->xGlobalRelease ){ - sJx9MPGlobal.pMutexMethods->xGlobalRelease(); - } - sJx9MPGlobal.pMutexMethods = 0; - } - sJx9MPGlobal.nThreadingLevel = 0; -#endif - if( sJx9MPGlobal.sAllocator.pMethods ){ - /* Release the memory backend */ - SyMemBackendRelease(&sJx9MPGlobal.sAllocator); - } - sJx9MPGlobal.nMagic = 0x1928; -} -/* - * [CAPIREF: jx9_lib_shutdown()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_lib_shutdown(void) -{ - if( sJx9MPGlobal.nMagic != JX9_LIB_MAGIC ){ - /* Already shut */ - return JX9_OK; - } - JX9CoreShutdown(); - return JX9_OK; -} -/* - * [CAPIREF: jx9_lib_signature()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE const char * jx9_lib_signature(void) -{ - return JX9_SIG; -} -/* - * [CAPIREF: jx9_init()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_init(jx9 **ppEngine) -{ - jx9 *pEngine; - int rc; -#if defined(UNTRUST) - if( ppEngine == 0 ){ - return JX9_CORRUPT; - } -#endif - *ppEngine = 0; - /* One-time automatic library initialization */ - rc = Jx9CoreInitialize(); - if( rc != JX9_OK ){ - return rc; - } - /* Allocate a new engine */ - pEngine = (jx9 *)SyMemBackendPoolAlloc(&sJx9MPGlobal.sAllocator, sizeof(jx9)); - if( pEngine == 0 ){ - return JX9_NOMEM; - } - /* Zero the structure */ - SyZero(pEngine, sizeof(jx9)); - /* Initialize engine fields */ - pEngine->nMagic = JX9_ENGINE_MAGIC; - rc = SyMemBackendInitFromParent(&pEngine->sAllocator, &sJx9MPGlobal.sAllocator); - if( rc != JX9_OK ){ - goto Release; - } -//#if defined(JX9_ENABLE_THREADS) -// SyMemBackendDisbaleMutexing(&pEngine->sAllocator); -//#endif - /* Default configuration */ - SyBlobInit(&pEngine->xConf.sErrConsumer, &pEngine->sAllocator); - /* Install a default compile-time error consumer routine */ - pEngine->xConf.xErr = jx9VmBlobConsumer; - pEngine->xConf.pErrData = &pEngine->xConf.sErrConsumer; - /* Built-in vfs */ - pEngine->pVfs = sJx9MPGlobal.pVfs; -#if defined(JX9_ENABLE_THREADS) - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE ){ - /* Associate a recursive mutex with this instance */ - pEngine->pMutex = SyMutexNew(sJx9MPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); - if( pEngine->pMutex == 0 ){ - rc = JX9_NOMEM; - goto Release; - } - } -#endif - /* Link to the list of active engines */ -#if defined(JX9_ENABLE_THREADS) - /* Enter the global mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ -#endif - MACRO_LD_PUSH(sJx9MPGlobal.pEngines, pEngine); - sJx9MPGlobal.nEngine++; -#if defined(JX9_ENABLE_THREADS) - /* Leave the global mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ -#endif - /* Write a pointer to the new instance */ - *ppEngine = pEngine; - return JX9_OK; -Release: - SyMemBackendRelease(&pEngine->sAllocator); - SyMemBackendPoolFree(&sJx9MPGlobal.sAllocator,pEngine); - return rc; -} -/* - * [CAPIREF: jx9_release()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_release(jx9 *pEngine) -{ - int rc; - if( JX9_ENGINE_MISUSE(pEngine) ){ - return JX9_CORRUPT; - } -#if defined(JX9_ENABLE_THREADS) - /* Acquire engine mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_ENGINE_RELEASE(pEngine) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - /* Release the engine */ - rc = EngineRelease(&(*pEngine)); -#if defined(JX9_ENABLE_THREADS) - /* Leave engine mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - /* Release engine mutex */ - SyMutexRelease(sJx9MPGlobal.pMutexMethods, pEngine->pMutex) /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif -#if defined(JX9_ENABLE_THREADS) - /* Enter the global mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ -#endif - /* Unlink from the list of active engines */ - MACRO_LD_REMOVE(sJx9MPGlobal.pEngines, pEngine); - sJx9MPGlobal.nEngine--; -#if defined(JX9_ENABLE_THREADS) - /* Leave the global mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, sJx9MPGlobal.pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel == JX9_THREAD_LEVEL_SINGLE */ -#endif - /* Release the memory chunk allocated to this engine */ - SyMemBackendPoolFree(&sJx9MPGlobal.sAllocator, pEngine); - return rc; -} -/* - * Compile a raw JX9 script. - * To execute a JX9 code, it must first be compiled into a bytecode program using this routine. - * If something goes wrong [i.e: compile-time error], your error log [i.e: error consumer callback] - * should display the appropriate error message and this function set ppVm to null and return - * an error code that is different from JX9_OK. Otherwise when the script is successfully compiled - * ppVm should hold the JX9 bytecode and it's safe to call [jx9_vm_exec(), jx9_vm_reset(), etc.]. - * This API does not actually evaluate the JX9 code. It merely compile and prepares the JX9 script - * for evaluation. - */ -static sxi32 ProcessScript( - jx9 *pEngine, /* Running JX9 engine */ - jx9_vm **ppVm, /* OUT: A pointer to the virtual machine */ - SyString *pScript, /* Raw JX9 script to compile */ - sxi32 iFlags, /* Compile-time flags */ - const char *zFilePath /* File path if script come from a file. NULL otherwise */ - ) -{ - jx9_vm *pVm; - int rc; - /* Allocate a new virtual machine */ - pVm = (jx9_vm *)SyMemBackendPoolAlloc(&pEngine->sAllocator, sizeof(jx9_vm)); - if( pVm == 0 ){ - /* If the supplied memory subsystem is so sick that we are unable to allocate - * a tiny chunk of memory, there is no much we can do here. */ - if( ppVm ){ - *ppVm = 0; - } - return JX9_NOMEM; - } - if( iFlags < 0 ){ - /* Default compile-time flags */ - iFlags = 0; - } - /* Initialize the Virtual Machine */ - rc = jx9VmInit(pVm, &(*pEngine)); - if( rc != JX9_OK ){ - SyMemBackendPoolFree(&pEngine->sAllocator, pVm); - if( ppVm ){ - *ppVm = 0; - } - return JX9_VM_ERR; - } - if( zFilePath ){ - /* Push processed file path */ - jx9VmPushFilePath(pVm, zFilePath, -1, TRUE, 0); - } - /* Reset the error message consumer */ - SyBlobReset(&pEngine->xConf.sErrConsumer); - /* Compile the script */ - jx9CompileScript(pVm, &(*pScript), iFlags); - if( pVm->sCodeGen.nErr > 0 || pVm == 0){ - sxu32 nErr = pVm->sCodeGen.nErr; - /* Compilation error or null ppVm pointer, release this VM */ - SyMemBackendRelease(&pVm->sAllocator); - SyMemBackendPoolFree(&pEngine->sAllocator, pVm); - if( ppVm ){ - *ppVm = 0; - } - return nErr > 0 ? JX9_COMPILE_ERR : JX9_OK; - } - /* Prepare the virtual machine for bytecode execution */ - rc = jx9VmMakeReady(pVm); - if( rc != JX9_OK ){ - goto Release; - } - /* Install local import path which is the current directory */ - jx9_vm_config(pVm, JX9_VM_CONFIG_IMPORT_PATH, "./"); -#if defined(JX9_ENABLE_THREADS) - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE ){ - /* Associate a recursive mutex with this instance */ - pVm->pMutex = SyMutexNew(sJx9MPGlobal.pMutexMethods, SXMUTEX_TYPE_RECURSIVE); - if( pVm->pMutex == 0 ){ - goto Release; - } - } -#endif - /* Script successfully compiled, link to the list of active virtual machines */ - MACRO_LD_PUSH(pEngine->pVms, pVm); - pEngine->iVm++; - /* Point to the freshly created VM */ - *ppVm = pVm; - /* Ready to execute JX9 bytecode */ - return JX9_OK; -Release: - SyMemBackendRelease(&pVm->sAllocator); - SyMemBackendPoolFree(&pEngine->sAllocator, pVm); - *ppVm = 0; - return JX9_VM_ERR; -} -/* - * [CAPIREF: jx9_compile()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_compile(jx9 *pEngine, const char *zSource, int nLen, jx9_vm **ppOutVm) -{ - SyString sScript; - int rc; - if( JX9_ENGINE_MISUSE(pEngine) ){ - return JX9_CORRUPT; - } - if( zSource == 0 ){ - /* Empty Jx9 statement ';' */ - zSource = ";"; - nLen = (int)sizeof(char); - } - if( nLen < 0 ){ - /* Compute input length automatically */ - nLen = (int)SyStrlen(zSource); - } - SyStringInitFromBuf(&sScript, zSource, nLen); -#if defined(JX9_ENABLE_THREADS) - /* Acquire engine mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_ENGINE_RELEASE(pEngine) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - /* Compile the script */ - rc = ProcessScript(&(*pEngine),ppOutVm,&sScript,0,0); -#if defined(JX9_ENABLE_THREADS) - /* Leave engine mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif - /* Compilation result */ - return rc; -} -/* - * [CAPIREF: jx9_compile_file()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_compile_file(jx9 *pEngine, const char *zFilePath, jx9_vm **ppOutVm) -{ - const jx9_vfs *pVfs; - int rc; - if( ppOutVm ){ - *ppOutVm = 0; - } - rc = JX9_OK; /* cc warning */ - if( JX9_ENGINE_MISUSE(pEngine) || SX_EMPTY_STR(zFilePath) ){ - return JX9_CORRUPT; - } -#if defined(JX9_ENABLE_THREADS) - /* Acquire engine mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_ENGINE_RELEASE(pEngine) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - /* - * Check if the underlying vfs implement the memory map - * [i.e: mmap() under UNIX/MapViewOfFile() under windows] function. - */ - pVfs = pEngine->pVfs; - if( pVfs == 0 || pVfs->xMmap == 0 ){ - /* Memory map routine not implemented */ - rc = JX9_IO_ERR; - }else{ - void *pMapView = 0; /* cc warning */ - jx9_int64 nSize = 0; /* cc warning */ - SyString sScript; - /* Try to get a memory view of the whole file */ - rc = pVfs->xMmap(zFilePath, &pMapView, &nSize); - if( rc != JX9_OK ){ - /* Assume an IO error */ - rc = JX9_IO_ERR; - }else{ - /* Compile the file */ - SyStringInitFromBuf(&sScript, pMapView, nSize); - rc = ProcessScript(&(*pEngine), ppOutVm, &sScript,0,zFilePath); - /* Release the memory view of the whole file */ - if( pVfs->xUnmap ){ - pVfs->xUnmap(pMapView, nSize); - } - } - } -#if defined(JX9_ENABLE_THREADS) - /* Leave engine mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif - /* Compilation result */ - return rc; -} -/* - * [CAPIREF: jx9_vm_config()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_vm_config(jx9_vm *pVm, int iConfigOp, ...) -{ - va_list ap; - int rc; - /* Ticket 1433-002: NULL VM is harmless operation */ - if ( JX9_VM_MISUSE(pVm) ){ - return JX9_CORRUPT; - } -#if defined(JX9_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_VM_RELEASE(pVm) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - /* Confiugure the virtual machine */ - va_start(ap, iConfigOp); - rc = jx9VmConfigure(&(*pVm), iConfigOp, ap); - va_end(ap); -#if defined(JX9_ENABLE_THREADS) - /* Leave VM mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -/* - * [CAPIREF: jx9_vm_release()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_vm_release(jx9_vm *pVm) -{ - jx9 *pEngine; - int rc; - /* Ticket 1433-002: NULL VM is harmless operation */ - if ( JX9_VM_MISUSE(pVm) ){ - return JX9_CORRUPT; - } -#if defined(JX9_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_VM_RELEASE(pVm) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - pEngine = pVm->pEngine; - rc = jx9VmRelease(&(*pVm)); -#if defined(JX9_ENABLE_THREADS) - /* Leave VM mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - /* Release VM mutex */ - SyMutexRelease(sJx9MPGlobal.pMutexMethods, pVm->pMutex) /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif - if( rc == JX9_OK ){ - /* Unlink from the list of active VM */ -#if defined(JX9_ENABLE_THREADS) - /* Acquire engine mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_ENGINE_RELEASE(pEngine) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - MACRO_LD_REMOVE(pEngine->pVms, pVm); - pEngine->iVm--; - /* Release the memory chunk allocated to this VM */ - SyMemBackendPoolFree(&pEngine->sAllocator, pVm); -#if defined(JX9_ENABLE_THREADS) - /* Leave engine mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pEngine->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif - } - return rc; -} -/* - * [CAPIREF: jx9_create_function()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_create_function(jx9_vm *pVm, const char *zName, int (*xFunc)(jx9_context *, int, jx9_value **), void *pUserData) -{ - SyString sName; - int rc; - /* Ticket 1433-002: NULL VM is harmless operation */ - if ( JX9_VM_MISUSE(pVm) ){ - return JX9_CORRUPT; - } - SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); - /* Remove leading and trailing white spaces */ - SyStringFullTrim(&sName); - /* Ticket 1433-003: NULL values are not allowed */ - if( sName.nByte < 1 || xFunc == 0 ){ - return JX9_CORRUPT; - } -#if defined(JX9_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_VM_RELEASE(pVm) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - /* Install the foreign function */ - rc = jx9VmInstallForeignFunction(&(*pVm), &sName, xFunc, pUserData); -#if defined(JX9_ENABLE_THREADS) - /* Leave VM mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -JX9_PRIVATE int jx9DeleteFunction(jx9_vm *pVm,const char *zName) -{ - jx9_user_func *pFunc = 0; /* cc warning */ - int rc; - /* Perform the deletion */ - rc = SyHashDeleteEntry(&pVm->hHostFunction, (const void *)zName, SyStrlen(zName), (void **)&pFunc); - if( rc == JX9_OK ){ - /* Release internal fields */ - SySetRelease(&pFunc->aAux); - SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pFunc->sName)); - SyMemBackendPoolFree(&pVm->sAllocator, pFunc); - } - return rc; -} -/* - * [CAPIREF: jx9_create_constant()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_create_constant(jx9_vm *pVm, const char *zName, void (*xExpand)(jx9_value *, void *), void *pUserData) -{ - SyString sName; - int rc; - /* Ticket 1433-002: NULL VM is harmless operation */ - if ( JX9_VM_MISUSE(pVm) ){ - return JX9_CORRUPT; - } - SyStringInitFromBuf(&sName, zName, SyStrlen(zName)); - /* Remove leading and trailing white spaces */ - SyStringFullTrim(&sName); - if( sName.nByte < 1 ){ - /* Empty constant name */ - return JX9_CORRUPT; - } - /* TICKET 1433-003: NULL pointer is harmless operation */ - if( xExpand == 0 ){ - return JX9_CORRUPT; - } -#if defined(JX9_ENABLE_THREADS) - /* Acquire VM mutex */ - SyMutexEnter(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ - if( sJx9MPGlobal.nThreadingLevel > JX9_THREAD_LEVEL_SINGLE && - JX9_THRD_VM_RELEASE(pVm) ){ - return JX9_ABORT; /* Another thread have released this instance */ - } -#endif - /* Perform the registration */ - rc = jx9VmRegisterConstant(&(*pVm), &sName, xExpand, pUserData); -#if defined(JX9_ENABLE_THREADS) - /* Leave VM mutex */ - SyMutexLeave(sJx9MPGlobal.pMutexMethods, pVm->pMutex); /* NO-OP if sJx9MPGlobal.nThreadingLevel != JX9_THREAD_LEVEL_MULTI */ -#endif - return rc; -} -JX9_PRIVATE int Jx9DeleteConstant(jx9_vm *pVm,const char *zName) -{ - jx9_constant *pCons; - int rc; - /* Query the constant hashtable */ - rc = SyHashDeleteEntry(&pVm->hConstant, (const void *)zName, SyStrlen(zName), (void **)&pCons); - if( rc == JX9_OK ){ - /* Perform the deletion */ - SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pCons->sName)); - SyMemBackendPoolFree(&pVm->sAllocator, pCons); - } - return rc; -} -/* - * [CAPIREF: jx9_new_scalar()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE jx9_value * jx9_new_scalar(jx9_vm *pVm) -{ - jx9_value *pObj; - /* Ticket 1433-002: NULL VM is harmless operation */ - if ( JX9_VM_MISUSE(pVm) ){ - return 0; - } - /* Allocate a new scalar variable */ - pObj = (jx9_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_value)); - if( pObj == 0 ){ - return 0; - } - /* Nullify the new scalar */ - jx9MemObjInit(pVm, pObj); - return pObj; -} -/* - * [CAPIREF: jx9_new_array()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE jx9_value * jx9_new_array(jx9_vm *pVm) -{ - jx9_hashmap *pMap; - jx9_value *pObj; - /* Ticket 1433-002: NULL VM is harmless operation */ - if ( JX9_VM_MISUSE(pVm) ){ - return 0; - } - /* Create a new hashmap first */ - pMap = jx9NewHashmap(&(*pVm), 0, 0); - if( pMap == 0 ){ - return 0; - } - /* Associate a new jx9_value with this hashmap */ - pObj = (jx9_value *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_value)); - if( pObj == 0 ){ - jx9HashmapRelease(pMap, TRUE); - return 0; - } - jx9MemObjInitFromArray(pVm, pObj, pMap); - return pObj; -} -/* - * [CAPIREF: jx9_release_value()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_release_value(jx9_vm *pVm, jx9_value *pValue) -{ - /* Ticket 1433-002: NULL VM is a harmless operation */ - if ( JX9_VM_MISUSE(pVm) ){ - return JX9_CORRUPT; - } - if( pValue ){ - /* Release the value */ - jx9MemObjRelease(pValue); - SyMemBackendPoolFree(&pVm->sAllocator, pValue); - } - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_to_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_to_int(jx9_value *pValue) -{ - int rc; - rc = jx9MemObjToInteger(pValue); - if( rc != JX9_OK ){ - return 0; - } - return (int)pValue->x.iVal; -} -/* - * [CAPIREF: jx9_value_to_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_to_bool(jx9_value *pValue) -{ - int rc; - rc = jx9MemObjToBool(pValue); - if( rc != JX9_OK ){ - return 0; - } - return (int)pValue->x.iVal; -} -/* - * [CAPIREF: jx9_value_to_int64()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE jx9_int64 jx9_value_to_int64(jx9_value *pValue) -{ - int rc; - rc = jx9MemObjToInteger(pValue); - if( rc != JX9_OK ){ - return 0; - } - return pValue->x.iVal; -} -/* - * [CAPIREF: jx9_value_to_double()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE double jx9_value_to_double(jx9_value *pValue) -{ - int rc; - rc = jx9MemObjToReal(pValue); - if( rc != JX9_OK ){ - return (double)0; - } - return (double)pValue->x.rVal; -} -/* - * [CAPIREF: jx9_value_to_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE const char * jx9_value_to_string(jx9_value *pValue, int *pLen) -{ - jx9MemObjToString(pValue); - if( SyBlobLength(&pValue->sBlob) > 0 ){ - SyBlobNullAppend(&pValue->sBlob); - if( pLen ){ - *pLen = (int)SyBlobLength(&pValue->sBlob); - } - return (const char *)SyBlobData(&pValue->sBlob); - }else{ - /* Return the empty string */ - if( pLen ){ - *pLen = 0; - } - return ""; - } -} -/* - * [CAPIREF: jx9_value_to_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void * jx9_value_to_resource(jx9_value *pValue) -{ - if( (pValue->iFlags & MEMOBJ_RES) == 0 ){ - /* Not a resource, return NULL */ - return 0; - } - return pValue->x.pOther; -} -/* - * [CAPIREF: jx9_value_compare()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_compare(jx9_value *pLeft, jx9_value *pRight, int bStrict) -{ - int rc; - if( pLeft == 0 || pRight == 0 ){ - /* TICKET 1433-24: NULL values is harmless operation */ - return 1; - } - /* Perform the comparison */ - rc = jx9MemObjCmp(&(*pLeft), &(*pRight), bStrict, 0); - /* Comparison result */ - return rc; -} -/* - * [CAPIREF: jx9_result_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_int(jx9_context *pCtx, int iValue) -{ - return jx9_value_int(pCtx->pRet, iValue); -} -/* - * [CAPIREF: jx9_result_int64()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_int64(jx9_context *pCtx, jx9_int64 iValue) -{ - return jx9_value_int64(pCtx->pRet, iValue); -} -/* - * [CAPIREF: jx9_result_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_bool(jx9_context *pCtx, int iBool) -{ - return jx9_value_bool(pCtx->pRet, iBool); -} -/* - * [CAPIREF: jx9_result_double()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_double(jx9_context *pCtx, double Value) -{ - return jx9_value_double(pCtx->pRet, Value); -} -/* - * [CAPIREF: jx9_result_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_null(jx9_context *pCtx) -{ - /* Invalidate any prior representation and set the NULL flag */ - jx9MemObjRelease(pCtx->pRet); - return JX9_OK; -} -/* - * [CAPIREF: jx9_result_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_string(jx9_context *pCtx, const char *zString, int nLen) -{ - return jx9_value_string(pCtx->pRet, zString, nLen); -} -/* - * [CAPIREF: jx9_result_string_format()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_string_format(jx9_context *pCtx, const char *zFormat, ...) -{ - jx9_value *p; - va_list ap; - int rc; - p = pCtx->pRet; - if( (p->iFlags & MEMOBJ_STRING) == 0 ){ - /* Invalidate any prior representation */ - jx9MemObjRelease(p); - MemObjSetType(p, MEMOBJ_STRING); - } - /* Format the given string */ - va_start(ap, zFormat); - rc = SyBlobFormatAp(&p->sBlob, zFormat, ap); - va_end(ap); - return rc; -} -/* - * [CAPIREF: jx9_result_value()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_value(jx9_context *pCtx, jx9_value *pValue) -{ - int rc = JX9_OK; - if( pValue == 0 ){ - jx9MemObjRelease(pCtx->pRet); - }else{ - rc = jx9MemObjStore(pValue, pCtx->pRet); - } - return rc; -} -/* - * [CAPIREF: jx9_result_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_result_resource(jx9_context *pCtx, void *pUserData) -{ - return jx9_value_resource(pCtx->pRet, pUserData); -} -/* - * [CAPIREF: jx9_context_new_scalar()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE jx9_value * jx9_context_new_scalar(jx9_context *pCtx) -{ - jx9_value *pVal; - pVal = jx9_new_scalar(pCtx->pVm); - if( pVal ){ - /* Record value address so it can be freed automatically - * when the calling function returns. - */ - SySetPut(&pCtx->sVar, (const void *)&pVal); - } - return pVal; -} -/* - * [CAPIREF: jx9_context_new_array()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE jx9_value * jx9_context_new_array(jx9_context *pCtx) -{ - jx9_value *pVal; - pVal = jx9_new_array(pCtx->pVm); - if( pVal ){ - /* Record value address so it can be freed automatically - * when the calling function returns. - */ - SySetPut(&pCtx->sVar, (const void *)&pVal); - } - return pVal; -} -/* - * [CAPIREF: jx9_context_release_value()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void jx9_context_release_value(jx9_context *pCtx, jx9_value *pValue) -{ - jx9VmReleaseContextValue(&(*pCtx), pValue); -} -/* - * [CAPIREF: jx9_context_alloc_chunk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void * jx9_context_alloc_chunk(jx9_context *pCtx, unsigned int nByte, int ZeroChunk, int AutoRelease) -{ - void *pChunk; - pChunk = SyMemBackendAlloc(&pCtx->pVm->sAllocator, nByte); - if( pChunk ){ - if( ZeroChunk ){ - /* Zero the memory chunk */ - SyZero(pChunk, nByte); - } - if( AutoRelease ){ - jx9_aux_data sAux; - /* Track the chunk so that it can be released automatically - * upon this context is destroyed. - */ - sAux.pAuxData = pChunk; - SySetPut(&pCtx->sChunk, (const void *)&sAux); - } - } - return pChunk; -} -/* - * Check if the given chunk address is registered in the call context - * chunk container. - * Return TRUE if registered.FALSE otherwise. - * Refer to [jx9_context_realloc_chunk(), jx9_context_free_chunk()]. - */ -static jx9_aux_data * ContextFindChunk(jx9_context *pCtx, void *pChunk) -{ - jx9_aux_data *aAux, *pAux; - sxu32 n; - if( SySetUsed(&pCtx->sChunk) < 1 ){ - /* Don't bother processing, the container is empty */ - return 0; - } - /* Perform the lookup */ - aAux = (jx9_aux_data *)SySetBasePtr(&pCtx->sChunk); - for( n = 0; n < SySetUsed(&pCtx->sChunk) ; ++n ){ - pAux = &aAux[n]; - if( pAux->pAuxData == pChunk ){ - /* Chunk found */ - return pAux; - } - } - /* No such allocated chunk */ - return 0; -} -/* - * [CAPIREF: jx9_context_realloc_chunk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void * jx9_context_realloc_chunk(jx9_context *pCtx, void *pChunk, unsigned int nByte) -{ - jx9_aux_data *pAux; - void *pNew; - pNew = SyMemBackendRealloc(&pCtx->pVm->sAllocator, pChunk, nByte); - if( pNew ){ - pAux = ContextFindChunk(pCtx, pChunk); - if( pAux ){ - pAux->pAuxData = pNew; - } - } - return pNew; -} -/* - * [CAPIREF: jx9_context_free_chunk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void jx9_context_free_chunk(jx9_context *pCtx, void *pChunk) -{ - jx9_aux_data *pAux; - if( pChunk == 0 ){ - /* TICKET-1433-93: NULL chunk is a harmless operation */ - return; - } - pAux = ContextFindChunk(pCtx, pChunk); - if( pAux ){ - /* Mark as destroyed */ - pAux->pAuxData = 0; - } - SyMemBackendFree(&pCtx->pVm->sAllocator, pChunk); -} -/* - * [CAPIREF: jx9_array_fetch()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE jx9_value * jx9_array_fetch(jx9_value *pArray, const char *zKey, int nByte) -{ - jx9_hashmap_node *pNode; - jx9_value *pValue; - jx9_value skey; - int rc; - /* Make sure we are dealing with a valid hashmap */ - if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ - return 0; - } - if( nByte < 0 ){ - nByte = (int)SyStrlen(zKey); - } - /* Convert the key to a jx9_value */ - jx9MemObjInit(pArray->pVm, &skey); - jx9MemObjStringAppend(&skey, zKey, (sxu32)nByte); - /* Perform the lookup */ - rc = jx9HashmapLookup((jx9_hashmap *)pArray->x.pOther, &skey, &pNode); - jx9MemObjRelease(&skey); - if( rc != JX9_OK ){ - /* No such entry */ - return 0; - } - /* Extract the target value */ - pValue = (jx9_value *)SySetAt(&pArray->pVm->aMemObj, pNode->nValIdx); - return pValue; -} -/* - * [CAPIREF: jx9_array_walk()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_array_walk(jx9_value *pArray, int (*xWalk)(jx9_value *pValue, jx9_value *, void *), void *pUserData) -{ - int rc; - if( xWalk == 0 ){ - return JX9_CORRUPT; - } - /* Make sure we are dealing with a valid hashmap */ - if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ - return JX9_CORRUPT; - } - /* Start the walk process */ - rc = jx9HashmapWalk((jx9_hashmap *)pArray->x.pOther, xWalk, pUserData); - return rc != JX9_OK ? JX9_ABORT /* User callback request an operation abort*/ : JX9_OK; -} -/* - * [CAPIREF: jx9_array_add_elem()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_array_add_elem(jx9_value *pArray, jx9_value *pKey, jx9_value *pValue) -{ - int rc; - /* Make sure we are dealing with a valid hashmap */ - if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ - return JX9_CORRUPT; - } - /* Perform the insertion */ - rc = jx9HashmapInsert((jx9_hashmap *)pArray->x.pOther, &(*pKey), &(*pValue)); - return rc; -} -/* - * [CAPIREF: jx9_array_add_strkey_elem()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_array_add_strkey_elem(jx9_value *pArray, const char *zKey, jx9_value *pValue) -{ - int rc; - /* Make sure we are dealing with a valid hashmap */ - if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ - return JX9_CORRUPT; - } - /* Perform the insertion */ - if( SX_EMPTY_STR(zKey) ){ - /* Empty key, assign an automatic index */ - rc = jx9HashmapInsert((jx9_hashmap *)pArray->x.pOther, 0, &(*pValue)); - }else{ - jx9_value sKey; - jx9MemObjInitFromString(pArray->pVm, &sKey, 0); - jx9MemObjStringAppend(&sKey, zKey, (sxu32)SyStrlen(zKey)); - rc = jx9HashmapInsert((jx9_hashmap *)pArray->x.pOther, &sKey, &(*pValue)); - jx9MemObjRelease(&sKey); - } - return rc; -} -/* - * [CAPIREF: jx9_array_count()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE unsigned int jx9_array_count(jx9_value *pArray) -{ - jx9_hashmap *pMap; - /* Make sure we are dealing with a valid hashmap */ - if( (pArray->iFlags & MEMOBJ_HASHMAP) == 0 ){ - return 0; - } - /* Point to the internal representation of the hashmap */ - pMap = (jx9_hashmap *)pArray->x.pOther; - return pMap->nEntry; -} -/* - * [CAPIREF: jx9_context_output()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_context_output(jx9_context *pCtx, const char *zString, int nLen) -{ - SyString sData; - int rc; - if( nLen < 0 ){ - nLen = (int)SyStrlen(zString); - } - SyStringInitFromBuf(&sData, zString, nLen); - rc = jx9VmOutputConsume(pCtx->pVm, &sData); - return rc; -} -/* - * [CAPIREF: jx9_context_throw_error()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_context_throw_error(jx9_context *pCtx, int iErr, const char *zErr) -{ - int rc = JX9_OK; - if( zErr ){ - rc = jx9VmThrowError(pCtx->pVm, &pCtx->pFunc->sName, iErr, zErr); - } - return rc; -} -/* - * [CAPIREF: jx9_context_throw_error_format()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_context_throw_error_format(jx9_context *pCtx, int iErr, const char *zFormat, ...) -{ - va_list ap; - int rc; - if( zFormat == 0){ - return JX9_OK; - } - va_start(ap, zFormat); - rc = jx9VmThrowErrorAp(pCtx->pVm, &pCtx->pFunc->sName, iErr, zFormat, ap); - va_end(ap); - return rc; -} -/* - * [CAPIREF: jx9_context_random_num()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE unsigned int jx9_context_random_num(jx9_context *pCtx) -{ - sxu32 n; - n = jx9VmRandomNum(pCtx->pVm); - return n; -} -/* - * [CAPIREF: jx9_context_random_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_context_random_string(jx9_context *pCtx, char *zBuf, int nBuflen) -{ - if( nBuflen < 3 ){ - return JX9_CORRUPT; - } - jx9VmRandomString(pCtx->pVm, zBuf, nBuflen); - return JX9_OK; -} -/* - * [CAPIREF: jx9_context_user_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void * jx9_context_user_data(jx9_context *pCtx) -{ - return pCtx->pFunc->pUserData; -} -/* - * [CAPIREF: jx9_context_push_aux_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_context_push_aux_data(jx9_context *pCtx, void *pUserData) -{ - jx9_aux_data sAux; - int rc; - sAux.pAuxData = pUserData; - rc = SySetPut(&pCtx->pFunc->aAux, (const void *)&sAux); - return rc; -} -/* - * [CAPIREF: jx9_context_peek_aux_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void * jx9_context_peek_aux_data(jx9_context *pCtx) -{ - jx9_aux_data *pAux; - pAux = (jx9_aux_data *)SySetPeek(&pCtx->pFunc->aAux); - return pAux ? pAux->pAuxData : 0; -} -/* - * [CAPIREF: jx9_context_pop_aux_data()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE void * jx9_context_pop_aux_data(jx9_context *pCtx) -{ - jx9_aux_data *pAux; - pAux = (jx9_aux_data *)SySetPop(&pCtx->pFunc->aAux); - return pAux ? pAux->pAuxData : 0; -} -/* - * [CAPIREF: jx9_context_result_buf_length()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE unsigned int jx9_context_result_buf_length(jx9_context *pCtx) -{ - return SyBlobLength(&pCtx->pRet->sBlob); -} -/* - * [CAPIREF: jx9_function_name()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE const char * jx9_function_name(jx9_context *pCtx) -{ - SyString *pName; - pName = &pCtx->pFunc->sName; - return pName->zString; -} -/* - * [CAPIREF: jx9_value_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_int(jx9_value *pVal, int iValue) -{ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - pVal->x.iVal = (jx9_int64)iValue; - MemObjSetType(pVal, MEMOBJ_INT); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_int64()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_int64(jx9_value *pVal, jx9_int64 iValue) -{ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - pVal->x.iVal = iValue; - MemObjSetType(pVal, MEMOBJ_INT); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_bool(jx9_value *pVal, int iBool) -{ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - pVal->x.iVal = iBool ? 1 : 0; - MemObjSetType(pVal, MEMOBJ_BOOL); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_null(jx9_value *pVal) -{ - /* Invalidate any prior representation and set the NULL flag */ - jx9MemObjRelease(pVal); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_double()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_double(jx9_value *pVal, double Value) -{ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - pVal->x.rVal = (jx9_real)Value; - MemObjSetType(pVal, MEMOBJ_REAL); - /* Try to get an integer representation also */ - jx9MemObjTryInteger(pVal); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_string(jx9_value *pVal, const char *zString, int nLen) -{ - if((pVal->iFlags & MEMOBJ_STRING) == 0 ){ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - MemObjSetType(pVal, MEMOBJ_STRING); - } - if( zString ){ - if( nLen < 0 ){ - /* Compute length automatically */ - nLen = (int)SyStrlen(zString); - } - SyBlobAppend(&pVal->sBlob, (const void *)zString, (sxu32)nLen); - } - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_string_format()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_string_format(jx9_value *pVal, const char *zFormat, ...) -{ - va_list ap; - int rc; - if((pVal->iFlags & MEMOBJ_STRING) == 0 ){ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - MemObjSetType(pVal, MEMOBJ_STRING); - } - va_start(ap, zFormat); - rc = SyBlobFormatAp(&pVal->sBlob, zFormat, ap); - va_end(ap); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_reset_string_cursor()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_reset_string_cursor(jx9_value *pVal) -{ - /* Reset the string cursor */ - SyBlobReset(&pVal->sBlob); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_resource(jx9_value *pVal, void *pUserData) -{ - /* Invalidate any prior representation */ - jx9MemObjRelease(pVal); - /* Reflect the new type */ - pVal->x.pOther = pUserData; - MemObjSetType(pVal, MEMOBJ_RES); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_release()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_release(jx9_value *pVal) -{ - jx9MemObjRelease(pVal); - return JX9_OK; -} -/* - * [CAPIREF: jx9_value_is_int()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_int(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_INT) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_float()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_float(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_REAL) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_bool()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_bool(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_BOOL) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_string()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_string(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_STRING) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_null()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_null(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_NULL) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_numeric()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_numeric(jx9_value *pVal) -{ - int rc; - rc = jx9MemObjIsNumeric(pVal); - return rc; -} -/* - * [CAPIREF: jx9_value_is_callable()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_callable(jx9_value *pVal) -{ - int rc; - rc = jx9VmIsCallable(pVal->pVm, pVal); - return rc; -} -/* - * [CAPIREF: jx9_value_is_scalar()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_scalar(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_SCALAR) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_json_array()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_json_array(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_HASHMAP) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_json_object()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_json_object(jx9_value *pVal) -{ - jx9_hashmap *pMap; - if( (pVal->iFlags & MEMOBJ_HASHMAP) == 0 ){ - return FALSE; - } - pMap = (jx9_hashmap *)pVal->x.pOther; - if( (pMap->iFlags & HASHMAP_JSON_OBJECT) == 0 ){ - return FALSE; - } - return TRUE; -} -/* - * [CAPIREF: jx9_value_is_resource()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_resource(jx9_value *pVal) -{ - return (pVal->iFlags & MEMOBJ_RES) ? TRUE : FALSE; -} -/* - * [CAPIREF: jx9_value_is_empty()] - * Please refer to the official documentation for function purpose and expected parameters. - */ -JX9_PRIVATE int jx9_value_is_empty(jx9_value *pVal) -{ - int rc; - rc = jx9MemObjIsEmpty(pVal); - return rc; -} -/* - * ---------------------------------------------------------- - * File: jx9_builtin.c - * MD5: 97ae6ddf8ded9fe14634060675e12f80 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: builtin.c v1.7 Win7 2012-12-13 00:01 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* This file implement built-in 'foreign' functions for the JX9 engine */ -/* - * Section: - * Variable handling Functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * bool is_bool($var) - * Finds out whether a variable is a boolean. - * Parameters - * $var: The variable being evaluated. - * Return - * TRUE if var is a boolean. False otherwise. - */ -static int jx9Builtin_is_bool(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_bool(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_float($var) - * bool is_real($var) - * bool is_double($var) - * Finds out whether a variable is a float. - * Parameters - * $var: The variable being evaluated. - * Return - * TRUE if var is a float. False otherwise. - */ -static int jx9Builtin_is_float(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_float(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_int($var) - * bool is_integer($var) - * bool is_long($var) - * Finds out whether a variable is an integer. - * Parameters - * $var: The variable being evaluated. - * Return - * TRUE if var is an integer. False otherwise. - */ -static int jx9Builtin_is_int(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_int(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_string($var) - * Finds out whether a variable is a string. - * Parameters - * $var: The variable being evaluated. - * Return - * TRUE if var is string. False otherwise. - */ -static int jx9Builtin_is_string(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_string(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_null($var) - * Finds out whether a variable is NULL. - * Parameters - * $var: The variable being evaluated. - * Return - * TRUE if var is NULL. False otherwise. - */ -static int jx9Builtin_is_null(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_null(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_numeric($var) - * Find out whether a variable is NULL. - * Parameters - * $var: The variable being evaluated. - * Return - * True if var is numeric. False otherwise. - */ -static int jx9Builtin_is_numeric(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_numeric(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_scalar($var) - * Find out whether a variable is a scalar. - * Parameters - * $var: The variable being evaluated. - * Return - * True if var is scalar. False otherwise. - */ -static int jx9Builtin_is_scalar(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_scalar(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_array($var) - * Find out whether a variable is an array. - * Parameters - * $var: The variable being evaluated. - * Return - * True if var is an array. False otherwise. - */ -static int jx9Builtin_is_array(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_json_array(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_object($var) - * Find out whether a variable is an object. - * Parameters - * $var: The variable being evaluated. - * Return - * True if var is an object. False otherwise. - */ -static int jx9Builtin_is_object(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_json_object(apArg[0]); - } - /* Query result */ - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * bool is_resource($var) - * Find out whether a variable is a resource. - * Parameters - * $var: The variable being evaluated. - * Return - * True if a resource. False otherwise. - */ -static int jx9Builtin_is_resource(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 0; /* Assume false by default */ - if( nArg > 0 ){ - res = jx9_value_is_resource(apArg[0]); - } - jx9_result_bool(pCtx, res); - return JX9_OK; -} -/* - * float floatval($var) - * Get float value of a variable. - * Parameter - * $var: The variable being processed. - * Return - * the float value of a variable. - */ -static int jx9Builtin_floatval(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg < 1 ){ - /* return 0.0 */ - jx9_result_double(pCtx, 0); - }else{ - double dval; - /* Perform the cast */ - dval = jx9_value_to_double(apArg[0]); - jx9_result_double(pCtx, dval); - } - return JX9_OK; -} -/* - * int intval($var) - * Get integer value of a variable. - * Parameter - * $var: The variable being processed. - * Return - * the int value of a variable. - */ -static int jx9Builtin_intval(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg < 1 ){ - /* return 0 */ - jx9_result_int(pCtx, 0); - }else{ - sxi64 iVal; - /* Perform the cast */ - iVal = jx9_value_to_int64(apArg[0]); - jx9_result_int64(pCtx, iVal); - } - return JX9_OK; -} -/* - * string strval($var) - * Get the string representation of a variable. - * Parameter - * $var: The variable being processed. - * Return - * the string value of a variable. - */ -static int jx9Builtin_strval(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg < 1 ){ - /* return NULL */ - jx9_result_null(pCtx); - }else{ - const char *zVal; - int iLen = 0; /* cc -O6 warning */ - /* Perform the cast */ - zVal = jx9_value_to_string(apArg[0], &iLen); - jx9_result_string(pCtx, zVal, iLen); - } - return JX9_OK; -} -/* - * bool empty($var) - * Determine whether a variable is empty. - * Parameters - * $var: The variable being checked. - * Return - * 0 if var has a non-empty and non-zero value.1 otherwise. - */ -static int jx9Builtin_empty(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int res = 1; /* Assume empty by default */ - if( nArg > 0 ){ - res = jx9_value_is_empty(apArg[0]); - } - jx9_result_bool(pCtx, res); - return JX9_OK; - -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifdef JX9_ENABLE_MATH_FUNC -/* - * Section: - * Math Functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -#include /* abs */ -#include -/* - * float sqrt(float $arg ) - * Square root of the given number. - * Parameter - * The number to process. - * Return - * The square root of arg or the special value Nan of failure. - */ -static int jx9Builtin_sqrt(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = sqrt(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float exp(float $arg ) - * Calculates the exponent of e. - * Parameter - * The number to process. - * Return - * 'e' raised to the power of arg. - */ -static int jx9Builtin_exp(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = exp(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float floor(float $arg ) - * Round fractions down. - * Parameter - * The number to process. - * Return - * Returns the next lowest integer value by rounding down value if necessary. - */ -static int jx9Builtin_floor(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = floor(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float cos(float $arg ) - * Cosine. - * Parameter - * The number to process. - * Return - * The cosine of arg. - */ -static int jx9Builtin_cos(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = cos(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float acos(float $arg ) - * Arc cosine. - * Parameter - * The number to process. - * Return - * The arc cosine of arg. - */ -static int jx9Builtin_acos(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = acos(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float cosh(float $arg ) - * Hyperbolic cosine. - * Parameter - * The number to process. - * Return - * The hyperbolic cosine of arg. - */ -static int jx9Builtin_cosh(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = cosh(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float sin(float $arg ) - * Sine. - * Parameter - * The number to process. - * Return - * The sine of arg. - */ -static int jx9Builtin_sin(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = sin(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float asin(float $arg ) - * Arc sine. - * Parameter - * The number to process. - * Return - * The arc sine of arg. - */ -static int jx9Builtin_asin(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = asin(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float sinh(float $arg ) - * Hyperbolic sine. - * Parameter - * The number to process. - * Return - * The hyperbolic sine of arg. - */ -static int jx9Builtin_sinh(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = sinh(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float ceil(float $arg ) - * Round fractions up. - * Parameter - * The number to process. - * Return - * The next highest integer value by rounding up value if necessary. - */ -static int jx9Builtin_ceil(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = ceil(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float tan(float $arg ) - * Tangent. - * Parameter - * The number to process. - * Return - * The tangent of arg. - */ -static int jx9Builtin_tan(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = tan(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float atan(float $arg ) - * Arc tangent. - * Parameter - * The number to process. - * Return - * The arc tangent of arg. - */ -static int jx9Builtin_atan(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = atan(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float tanh(float $arg ) - * Hyperbolic tangent. - * Parameter - * The number to process. - * Return - * The Hyperbolic tangent of arg. - */ -static int jx9Builtin_tanh(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = tanh(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float atan2(float $y, float $x) - * Arc tangent of two variable. - * Parameter - * $y = Dividend parameter. - * $x = Divisor parameter. - * Return - * The arc tangent of y/x in radian. - */ -static int jx9Builtin_atan2(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x, y; - if( nArg < 2 ){ - /* Missing arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - y = jx9_value_to_double(apArg[0]); - x = jx9_value_to_double(apArg[1]); - /* Perform the requested operation */ - r = atan2(y, x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float/int64 abs(float/int64 $arg ) - * Absolute value. - * Parameter - * The number to process. - * Return - * The absolute value of number. - */ -static int jx9Builtin_abs(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int is_float; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - is_float = jx9_value_is_float(apArg[0]); - if( is_float ){ - double r, x; - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = fabs(x); - jx9_result_double(pCtx, r); - }else{ - int r, x; - x = jx9_value_to_int(apArg[0]); - /* Perform the requested operation */ - r = abs(x); - jx9_result_int(pCtx, r); - } - return JX9_OK; -} -/* - * float log(float $arg, [int/float $base]) - * Natural logarithm. - * Parameter - * $arg: The number to process. - * $base: The optional logarithmic base to use. (only base-10 is supported) - * Return - * The logarithm of arg to base, if given, or the natural logarithm. - * Note: - * only Natural log and base-10 log are supported. - */ -static int jx9Builtin_log(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - if( nArg == 2 && jx9_value_is_numeric(apArg[1]) && jx9_value_to_int(apArg[1]) == 10 ){ - /* Base-10 log */ - r = log10(x); - }else{ - r = log(x); - } - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float log10(float $arg ) - * Base-10 logarithm. - * Parameter - * The number to process. - * Return - * The Base-10 logarithm of the given number. - */ -static int jx9Builtin_log10(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - /* Perform the requested operation */ - r = log10(x); - /* store the result back */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * number pow(number $base, number $exp) - * Exponential expression. - * Parameter - * base - * The base to use. - * exp - * The exponent. - * Return - * base raised to the power of exp. - * If the result can be represented as integer it will be returned - * as type integer, else it will be returned as type float. - */ -static int jx9Builtin_pow(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double r, x, y; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - x = jx9_value_to_double(apArg[0]); - y = jx9_value_to_double(apArg[1]); - /* Perform the requested operation */ - r = pow(x, y); - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float pi(void) - * Returns an approximation of pi. - * Note - * you can use the M_PI constant which yields identical results to pi(). - * Return - * The value of pi as float. - */ -static int jx9Builtin_pi(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - jx9_result_double(pCtx, JX9_PI); - return JX9_OK; -} -/* - * float fmod(float $x, float $y) - * Returns the floating point remainder (modulo) of the division of the arguments. - * Parameters - * $x - * The dividend - * $y - * The divisor - * Return - * The floating point remainder of x/y. - */ -static int jx9Builtin_fmod(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double x, y, r; - if( nArg < 2 ){ - /* Missing arguments */ - jx9_result_double(pCtx, 0); - return JX9_OK; - } - /* Extract given arguments */ - x = jx9_value_to_double(apArg[0]); - y = jx9_value_to_double(apArg[1]); - /* Perform the requested operation */ - r = fmod(x, y); - /* Processing result */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -/* - * float hypot(float $x, float $y) - * Calculate the length of the hypotenuse of a right-angle triangle . - * Parameters - * $x - * Length of first side - * $y - * Length of first side - * Return - * Calculated length of the hypotenuse. - */ -static int jx9Builtin_hypot(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - double x, y, r; - if( nArg < 2 ){ - /* Missing arguments */ - jx9_result_double(pCtx, 0); - return JX9_OK; - } - /* Extract given arguments */ - x = jx9_value_to_double(apArg[0]); - y = jx9_value_to_double(apArg[1]); - /* Perform the requested operation */ - r = hypot(x, y); - /* Processing result */ - jx9_result_double(pCtx, r); - return JX9_OK; -} -#endif /* JX9_ENABLE_MATH_FUNC */ -/* - * float round ( float $val [, int $precision = 0 [, int $mode = JX9_ROUND_HALF_UP ]] ) - * Exponential expression. - * Parameter - * $val - * The value to round. - * $precision - * The optional number of decimal digits to round to. - * $mode - * One of JX9_ROUND_HALF_UP, JX9_ROUND_HALF_DOWN, JX9_ROUND_HALF_EVEN, or JX9_ROUND_HALF_ODD. - * (not supported). - * Return - * The rounded value. - */ -static int jx9Builtin_round(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int n = 0; - double r; - if( nArg < 1 ){ - /* Missing argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the precision if available */ - if( nArg > 1 ){ - n = jx9_value_to_int(apArg[1]); - if( n>30 ){ - n = 30; - } - if( n<0 ){ - n = 0; - } - } - r = jx9_value_to_double(apArg[0]); - /* If Y==0 and X will fit in a 64-bit int, - * handle the rounding directly.Otherwise - * use our own cutsom printf [i.e:SyBufferFormat()]. - */ - if( n==0 && r>=0 && r= 0xc0 ){ - /* UTF-8 stream */ - zString++; - while( zString < zEnd && (((unsigned char)zString[0] & 0xc0) == 0x80) ){ - zString++; - } - }else{ - if( SyisHex(zString[0]) ){ - break; - } - /* Ignore */ - zString++; - } - } - if( zString < zEnd ){ - /* Cast */ - SyHexStrToInt64(zString, (sxu32)(zEnd-zString), (void *)&iVal, 0); - } - }else{ - /* Extract as a 64-bit integer */ - iVal = jx9_value_to_int64(apArg[0]); - } - /* Return the number */ - jx9_result_int64(pCtx, iVal); - return JX9_OK; -} -/* - * int64 bindec(string $bin_string) - * Binary to decimal. - * Parameters - * $bin_string - * The binary string to convert - * Return - * Returns the decimal equivalent of the binary number represented by the binary_string argument. - */ -static int jx9Builtin_bindec(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString; - jx9_int64 iVal; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return -1 */ - jx9_result_int(pCtx, -1); - return JX9_OK; - } - iVal = 0; - if( jx9_value_is_string(apArg[0]) ){ - /* Extract the given string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen > 0 ){ - /* Perform a binary cast */ - SyBinaryStrToInt64(zString, (sxu32)nLen, (void *)&iVal, 0); - } - }else{ - /* Extract as a 64-bit integer */ - iVal = jx9_value_to_int64(apArg[0]); - } - /* Return the number */ - jx9_result_int64(pCtx, iVal); - return JX9_OK; -} -/* - * int64 octdec(string $oct_string) - * Octal to decimal. - * Parameters - * $oct_string - * The octal string to convert - * Return - * Returns the decimal equivalent of the octal number represented by the octal_string argument. - */ -static int jx9Builtin_octdec(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString; - jx9_int64 iVal; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return -1 */ - jx9_result_int(pCtx, -1); - return JX9_OK; - } - iVal = 0; - if( jx9_value_is_string(apArg[0]) ){ - /* Extract the given string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen > 0 ){ - /* Perform the cast */ - SyOctalStrToInt64(zString, (sxu32)nLen, (void *)&iVal, 0); - } - }else{ - /* Extract as a 64-bit integer */ - iVal = jx9_value_to_int64(apArg[0]); - } - /* Return the number */ - jx9_result_int64(pCtx, iVal); - return JX9_OK; -} -/* - * string base_convert(string $number, int $frombase, int $tobase) - * Convert a number between arbitrary bases. - * Parameters - * $number - * The number to convert - * $frombase - * The base number is in - * $tobase - * The base to convert number to - * Return - * Number converted to base tobase - */ -static int jx9Builtin_base_convert(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int nLen, iFbase, iTobase; - const char *zNum; - jx9_int64 iNum; - if( nArg < 3 ){ - /* Return the empty string*/ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Base numbers */ - iFbase = jx9_value_to_int(apArg[1]); - iTobase = jx9_value_to_int(apArg[2]); - if( jx9_value_is_string(apArg[0]) ){ - /* Extract the target number */ - zNum = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Return the empty string*/ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Base conversion */ - switch(iFbase){ - case 16: - /* Hex */ - SyHexStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0); - break; - case 8: - /* Octal */ - SyOctalStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0); - break; - case 2: - /* Binary */ - SyBinaryStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0); - break; - default: - /* Decimal */ - SyStrToInt64(zNum, (sxu32)nLen, (void *)&iNum, 0); - break; - } - }else{ - iNum = jx9_value_to_int64(apArg[0]); - } - switch(iTobase){ - case 16: - /* Hex */ - jx9_result_string_format(pCtx, "%qx", iNum); /* Quad hex */ - break; - case 8: - /* Octal */ - jx9_result_string_format(pCtx, "%qo", iNum); /* Quad octal */ - break; - case 2: - /* Binary */ - jx9_result_string_format(pCtx, "%qB", iNum); /* Quad binary */ - break; - default: - /* Decimal */ - jx9_result_string_format(pCtx, "%qd", iNum); /* Quad decimal */ - break; - } - return JX9_OK; -} -/* - * Section: - * String handling Functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * string substr(string $string, int $start[, int $length ]) - * Return part of a string. - * Parameters - * $string - * The input string. Must be one character or longer. - * $start - * If start is non-negative, the returned string will start at the start'th position - * in string, counting from zero. For instance, in the string 'abcdef', the character - * at position 0 is 'a', the character at position 2 is 'c', and so forth. - * If start is negative, the returned string will start at the start'th character - * from the end of string. - * If string is less than or equal to start characters long, FALSE will be returned. - * $length - * If length is given and is positive, the string returned will contain at most length - * characters beginning from start (depending on the length of string). - * If length is given and is negative, then that many characters will be omitted from - * the end of string (after the start position has been calculated when a start is negative). - * If start denotes the position of this truncation or beyond, false will be returned. - * If length is given and is 0, FALSE or NULL an empty string will be returned. - * If length is omitted, the substring starting from start until the end of the string - * will be returned. - * Return - * Returns the extracted part of string, or FALSE on failure or an empty string. - */ -static int jx9Builtin_substr(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zSource, *zOfft; - int nOfft, nLen, nSrcLen; - if( nArg < 2 ){ - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zSource = jx9_value_to_string(apArg[0], &nSrcLen); - if( nSrcLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = nSrcLen; /* cc warning */ - /* Extract the offset */ - nOfft = jx9_value_to_int(apArg[1]); - if( nOfft < 0 ){ - zOfft = &zSource[nSrcLen+nOfft]; - if( zOfft < zSource ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = (int)(&zSource[nSrcLen]-zOfft); - nOfft = (int)(zOfft-zSource); - }else if( nOfft >= nSrcLen ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - }else{ - zOfft = &zSource[nOfft]; - nLen = nSrcLen - nOfft; - } - if( nArg > 2 ){ - /* Extract the length */ - nLen = jx9_value_to_int(apArg[2]); - if( nLen == 0 ){ - /* Invalid length, return an empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - }else if( nLen < 0 ){ - nLen = nSrcLen + nLen - nOfft; - if( nLen < 1 ){ - /* Invalid length */ - nLen = nSrcLen - nOfft; - } - } - if( nLen + nOfft > nSrcLen ){ - /* Invalid length */ - nLen = nSrcLen - nOfft; - } - } - /* Return the substring */ - jx9_result_string(pCtx, zOfft, nLen); - return JX9_OK; -} -/* - * int substr_compare(string $main_str, string $str , int $offset[, int $length[, bool $case_insensitivity = false ]]) - * Binary safe comparison of two strings from an offset, up to length characters. - * Parameters - * $main_str - * The main string being compared. - * $str - * The secondary string being compared. - * $offset - * The start position for the comparison. If negative, it starts counting from - * the end of the string. - * $length - * The length of the comparison. The default value is the largest of the length - * of the str compared to the length of main_str less the offset. - * $case_insensitivity - * If case_insensitivity is TRUE, comparison is case insensitive. - * Return - * Returns < 0 if main_str from position offset is less than str, > 0 if it is greater than - * str, and 0 if they are equal. If offset is equal to or greater than the length of main_str - * or length is set and is less than 1, substr_compare() prints a warning and returns FALSE. - */ -static int jx9Builtin_substr_compare(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zSource, *zOfft, *zSub; - int nOfft, nLen, nSrcLen, nSublen; - int iCase = 0; - int rc; - if( nArg < 3 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zSource = jx9_value_to_string(apArg[0], &nSrcLen); - if( nSrcLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = nSrcLen; /* cc warning */ - /* Extract the substring */ - zSub = jx9_value_to_string(apArg[1], &nSublen); - if( nSublen < 1 || nSublen > nSrcLen){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the offset */ - nOfft = jx9_value_to_int(apArg[2]); - if( nOfft < 0 ){ - zOfft = &zSource[nSrcLen+nOfft]; - if( zOfft < zSource ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = (int)(&zSource[nSrcLen]-zOfft); - nOfft = (int)(zOfft-zSource); - }else if( nOfft >= nSrcLen ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - }else{ - zOfft = &zSource[nOfft]; - nLen = nSrcLen - nOfft; - } - if( nArg > 3 ){ - /* Extract the length */ - nLen = jx9_value_to_int(apArg[3]); - if( nLen < 1 ){ - /* Invalid length */ - jx9_result_int(pCtx, 1); - return JX9_OK; - }else if( nLen + nOfft > nSrcLen ){ - /* Invalid length */ - nLen = nSrcLen - nOfft; - } - if( nArg > 4 ){ - /* Case-sensitive or not */ - iCase = jx9_value_to_bool(apArg[4]); - } - } - /* Perform the comparison */ - if( iCase ){ - rc = SyStrnicmp(zOfft, zSub, (sxu32)nLen); - }else{ - rc = SyStrncmp(zOfft, zSub, (sxu32)nLen); - } - /* Comparison result */ - jx9_result_int(pCtx, rc); - return JX9_OK; -} -/* - * int substr_count(string $haystack, string $needle[, int $offset = 0 [, int $length ]]) - * Count the number of substring occurrences. - * Parameters - * $haystack - * The string to search in - * $needle - * The substring to search for - * $offset - * The offset where to start counting - * $length (NOT USED) - * The maximum length after the specified offset to search for the substring. - * It outputs a warning if the offset plus the length is greater than the haystack length. - * Return - * Toral number of substring occurrences. - */ -static int jx9Builtin_substr_count(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zText, *zPattern, *zEnd; - int nTextlen, nPatlen; - int iCount = 0; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the haystack */ - zText = jx9_value_to_string(apArg[0], &nTextlen); - /* Point to the neddle */ - zPattern = jx9_value_to_string(apArg[1], &nPatlen); - if( nTextlen < 1 || nPatlen < 1 || nPatlen > nTextlen ){ - /* NOOP, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - if( nArg > 2 ){ - int nOfft; - /* Extract the offset */ - nOfft = jx9_value_to_int(apArg[2]); - if( nOfft < 0 || nOfft > nTextlen ){ - /* Invalid offset, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the desired offset */ - zText = &zText[nOfft]; - /* Adjust length */ - nTextlen -= nOfft; - } - /* Point to the end of the string */ - zEnd = &zText[nTextlen]; - if( nArg > 3 ){ - int nLen; - /* Extract the length */ - nLen = jx9_value_to_int(apArg[3]); - if( nLen < 0 || nLen > nTextlen ){ - /* Invalid length, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Adjust pointer */ - nTextlen = nLen; - zEnd = &zText[nTextlen]; - } - /* Perform the search */ - for(;;){ - rc = SyBlobSearch((const void *)zText, (sxu32)(zEnd-zText), (const void *)zPattern, nPatlen, &nOfft); - if( rc != SXRET_OK ){ - /* Pattern not found, break immediately */ - break; - } - /* Increment counter and update the offset */ - iCount++; - zText += nOfft + nPatlen; - if( zText >= zEnd ){ - break; - } - } - /* Pattern count */ - jx9_result_int(pCtx, iCount); - return JX9_OK; -} -/* - * string chunk_split(string $body[, int $chunklen = 76 [, string $end = "\r\n" ]]) - * Split a string into smaller chunks. - * Parameters - * $body - * The string to be chunked. - * $chunklen - * The chunk length. - * $end - * The line ending sequence. - * Return - * The chunked string or NULL on failure. - */ -static int jx9Builtin_chunk_split(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn, *zEnd, *zSep = "\r\n"; - int nSepLen, nChunkLen, nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Nothing to split, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* initialize/Extract arguments */ - nSepLen = (int)sizeof("\r\n") - 1; - nChunkLen = 76; - zIn = jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nArg > 1 ){ - /* Chunk length */ - nChunkLen = jx9_value_to_int(apArg[1]); - if( nChunkLen < 1 ){ - /* Switch back to the default length */ - nChunkLen = 76; - } - if( nArg > 2 ){ - /* Separator */ - zSep = jx9_value_to_string(apArg[2], &nSepLen); - if( nSepLen < 1 ){ - /* Switch back to the default separator */ - zSep = "\r\n"; - nSepLen = (int)sizeof("\r\n") - 1; - } - } - } - /* Perform the requested operation */ - if( nChunkLen > nLen ){ - /* Nothing to split, return the string and the separator */ - jx9_result_string_format(pCtx, "%.*s%.*s", nLen, zIn, nSepLen, zSep); - return JX9_OK; - } - while( zIn < zEnd ){ - if( nChunkLen > (int)(zEnd-zIn) ){ - nChunkLen = (int)(zEnd - zIn); - } - /* Append the chunk and the separator */ - jx9_result_string_format(pCtx, "%.*s%.*s", nChunkLen, zIn, nSepLen, zSep); - /* Point beyond the chunk */ - zIn += nChunkLen; - } - return JX9_OK; -} -/* - * string htmlspecialchars(string $string [, int $flags = ENT_COMPAT | ENT_HTML401 [, string $charset]]) - * HTML escaping of special characters. - * The translations performed are: - * '&' (ampersand) ==> '&' - * '"' (double quote) ==> '"' when ENT_NOQUOTES is not set. - * "'" (single quote) ==> ''' only when ENT_QUOTES is set. - * '<' (less than) ==> '<' - * '>' (greater than) ==> '>' - * Parameters - * $string - * The string being converted. - * $flags - * A bitmask of one or more of the following flags, which specify how to handle quotes. - * The default is ENT_COMPAT | ENT_HTML401. - * ENT_COMPAT Will convert double-quotes and leave single-quotes alone. - * ENT_QUOTES Will convert both double and single quotes. - * ENT_NOQUOTES Will leave both double and single quotes unconverted. - * ENT_IGNORE Silently discard invalid code unit sequences instead of returning an empty string. - * $charset - * Defines character set used in conversion. The default character set is ISO-8859-1. (Not used) - * Return - * The escaped string or NULL on failure. - */ -static int jx9Builtin_htmlspecialchars(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zCur, *zIn, *zEnd; - int iFlags = 0x01|0x40; /* ENT_COMPAT | ENT_HTML401 */ - int nLen, c; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - /* Extract the flags if available */ - if( nArg > 1 ){ - iFlags = jx9_value_to_int(apArg[1]); - if( iFlags < 0 ){ - iFlags = 0x01|0x40; - } - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - break; - } - zCur = zIn; - while( zIn < zEnd && zIn[0] != '&' && zIn[0] != '\'' && zIn[0] != '"' && zIn[0] != '<' && zIn[0] != '>' ){ - zIn++; - } - if( zCur < zIn ){ - /* Append the raw string verbatim */ - jx9_result_string(pCtx, zCur, (int)(zIn-zCur)); - } - if( zIn >= zEnd ){ - break; - } - c = zIn[0]; - if( c == '&' ){ - /* Expand '&' */ - jx9_result_string(pCtx, "&", (int)sizeof("&")-1); - }else if( c == '<' ){ - /* Expand '<' */ - jx9_result_string(pCtx, "<", (int)sizeof("<")-1); - }else if( c == '>' ){ - /* Expand '>' */ - jx9_result_string(pCtx, ">", (int)sizeof(">")-1); - }else if( c == '\'' ){ - if( iFlags & 0x02 /*ENT_QUOTES*/ ){ - /* Expand ''' */ - jx9_result_string(pCtx, "'", (int)sizeof("'")-1); - }else{ - /* Leave the single quote untouched */ - jx9_result_string(pCtx, "'", (int)sizeof(char)); - } - }else if( c == '"' ){ - if( (iFlags & 0x04) == 0 /*ENT_NOQUOTES*/ ){ - /* Expand '"' */ - jx9_result_string(pCtx, """, (int)sizeof(""")-1); - }else{ - /* Leave the double quote untouched */ - jx9_result_string(pCtx, "\"", (int)sizeof(char)); - } - } - /* Ignore the unsafe HTML character */ - zIn++; - } - return JX9_OK; -} -/* - * string htmlspecialchars_decode(string $string[, int $quote_style = ENT_COMPAT ]) - * Unescape HTML entities. - * Parameters - * $string - * The string to decode - * $quote_style - * The quote style. One of the following constants: - * ENT_COMPAT Will convert double-quotes and leave single-quotes alone (default) - * ENT_QUOTES Will convert both double and single quotes - * ENT_NOQUOTES Will leave both double and single quotes unconverted - * Return - * The unescaped string or NULL on failure. - */ -static int jx9Builtin_htmlspecialchars_decode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zCur, *zIn, *zEnd; - int iFlags = 0x01; /* ENT_COMPAT */ - int nLen, nJump; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - /* Extract the flags if available */ - if( nArg > 1 ){ - iFlags = jx9_value_to_int(apArg[1]); - if( iFlags < 0 ){ - iFlags = 0x01; - } - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - break; - } - zCur = zIn; - while( zIn < zEnd && zIn[0] != '&' ){ - zIn++; - } - if( zCur < zIn ){ - /* Append the raw string verbatim */ - jx9_result_string(pCtx, zCur, (int)(zIn-zCur)); - } - nLen = (int)(zEnd-zIn); - nJump = (int)sizeof(char); - if( nLen >= (int)sizeof("&")-1 && SyStrnicmp(zIn, "&", sizeof("&")-1) == 0 ){ - /* & ==> '&' */ - jx9_result_string(pCtx, "&", (int)sizeof(char)); - nJump = (int)sizeof("&")-1; - }else if( nLen >= (int)sizeof("<")-1 && SyStrnicmp(zIn, "<", sizeof("<")-1) == 0 ){ - /* < ==> < */ - jx9_result_string(pCtx, "<", (int)sizeof(char)); - nJump = (int)sizeof("<")-1; - }else if( nLen >= (int)sizeof(">")-1 && SyStrnicmp(zIn, ">", sizeof(">")-1) == 0 ){ - /* > ==> '>' */ - jx9_result_string(pCtx, ">", (int)sizeof(char)); - nJump = (int)sizeof(">")-1; - }else if( nLen >= (int)sizeof(""")-1 && SyStrnicmp(zIn, """, sizeof(""")-1) == 0 ){ - /* " ==> '"' */ - if( (iFlags & 0x04) == 0 /*ENT_NOQUOTES*/ ){ - jx9_result_string(pCtx, "\"", (int)sizeof(char)); - }else{ - /* Leave untouched */ - jx9_result_string(pCtx, """, (int)sizeof(""")-1); - } - nJump = (int)sizeof(""")-1; - }else if( nLen >= (int)sizeof("'")-1 && SyStrnicmp(zIn, "'", sizeof("'")-1) == 0 ){ - /* ' ==> ''' */ - if( iFlags & 0x02 /*ENT_QUOTES*/ ){ - /* Expand ''' */ - jx9_result_string(pCtx, "'", (int)sizeof(char)); - }else{ - /* Leave untouched */ - jx9_result_string(pCtx, "'", (int)sizeof("'")-1); - } - nJump = (int)sizeof("'")-1; - }else if( nLen >= (int)sizeof(char) ){ - /* expand '&' */ - jx9_result_string(pCtx, "&", (int)sizeof(char)); - }else{ - /* No more input to process */ - break; - } - zIn += nJump; - } - return JX9_OK; -} -/* HTML encoding/Decoding table - * Source: Symisc RunTime API.[chm@symisc.net] - */ -static const char *azHtmlEscape[] = { - "<", "<", ">", ">", "&", "&", """, "\"", "'", "'", - "!", "!", "$", "$", "#", "#", "%", "%", "(", "(", - ")", ")", "{", "{", "}", "}", "=", "=", "+", "+", - "?", "?", "[", "[", "]", "]", "@", "@", ",", "," - }; -/* - * array get_html_translation_table(void) - * Returns the translation table used by htmlspecialchars() and htmlentities(). - * Parameters - * None - * Return - * The translation table as an array or NULL on failure. - */ -static int jx9Builtin_get_html_translation_table(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue; - sxu32 n; - /* Element value */ - pValue = jx9_context_new_scalar(pCtx); - if( pValue == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Make the table */ - for( n = 0 ; n < SX_ARRAYSIZE(azHtmlEscape) ; n += 2 ){ - /* Prepare the value */ - jx9_value_string(pValue, azHtmlEscape[n], -1 /* Compute length automatically */); - /* Insert the value */ - jx9_array_add_strkey_elem(pArray, azHtmlEscape[n+1], pValue); - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - } - /* - * Return the array. - * Don't worry about freeing memory, everything will be automatically - * released upon we return from this function. - */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * string htmlentities( string $string [, int $flags = ENT_COMPAT | ENT_HTML401]); - * Convert all applicable characters to HTML entities - * Parameters - * $string - * The input string. - * $flags - * A bitmask of one or more of the flags (see block-comment on jx9Builtin_htmlspecialchars()) - * Return - * The encoded string. - */ -static int jx9Builtin_htmlentities(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int iFlags = 0x01; /* ENT_COMPAT */ - const char *zIn, *zEnd; - int nLen, c; - sxu32 n; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - /* Extract the flags if available */ - if( nArg > 1 ){ - iFlags = jx9_value_to_int(apArg[1]); - if( iFlags < 0 ){ - iFlags = 0x01; - } - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - c = zIn[0]; - /* Perform a linear lookup on the decoding table */ - for( n = 0 ; n < SX_ARRAYSIZE(azHtmlEscape) ; n += 2 ){ - if( azHtmlEscape[n+1][0] == c ){ - /* Got one */ - break; - } - } - if( n < SX_ARRAYSIZE(azHtmlEscape) ){ - /* Output the safe sequence [i.e: '<' ==> '<"] */ - if( c == '"' && (iFlags & 0x04) /*ENT_NOQUOTES*/ ){ - /* Expand the double quote verbatim */ - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - }else if(c == '\'' && ((iFlags & 0x02 /*ENT_QUOTES*/) == 0 || (iFlags & 0x04) /*ENT_NOQUOTES*/) ){ - /* expand single quote verbatim */ - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - }else{ - jx9_result_string(pCtx, azHtmlEscape[n], -1/*Compute length automatically */); - } - }else{ - /* Output character verbatim */ - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - } - zIn++; - } - return JX9_OK; -} -/* - * string html_entity_decode(string $string [, int $quote_style = ENT_COMPAT [, string $charset = 'UTF-8' ]]) - * Perform the reverse operation of html_entity_decode(). - * Parameters - * $string - * The input string. - * $flags - * A bitmask of one or more of the flags (see comment on jx9Builtin_htmlspecialchars()) - * Return - * The decoded string. - */ -static int jx9Builtin_html_entity_decode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zCur, *zIn, *zEnd; - int iFlags = 0x01; /* ENT_COMPAT */ - int nLen; - sxu32 n; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - /* Extract the flags if available */ - if( nArg > 1 ){ - iFlags = jx9_value_to_int(apArg[1]); - if( iFlags < 0 ){ - iFlags = 0x01; - } - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - zCur = zIn; - while( zIn < zEnd && zIn[0] != '&' ){ - zIn++; - } - if( zCur < zIn ){ - /* Append raw string verbatim */ - jx9_result_string(pCtx, zCur, (int)(zIn-zCur)); - } - if( zIn >= zEnd ){ - break; - } - nLen = (int)(zEnd-zIn); - /* Find an encoded sequence */ - for(n = 0 ; n < SX_ARRAYSIZE(azHtmlEscape) ; n += 2 ){ - int iLen = (int)SyStrlen(azHtmlEscape[n]); - if( nLen >= iLen && SyStrnicmp(zIn, azHtmlEscape[n], (sxu32)iLen) == 0 ){ - /* Got one */ - zIn += iLen; - break; - } - } - if( n < SX_ARRAYSIZE(azHtmlEscape) ){ - int c = azHtmlEscape[n+1][0]; - /* Output the decoded character */ - if( c == '\'' && ((iFlags & 0x02) == 0 /*ENT_QUOTES*/|| (iFlags & 0x04) /*ENT_NOQUOTES*/) ){ - /* Do not process single quotes */ - jx9_result_string(pCtx, azHtmlEscape[n], -1); - }else if( c == '"' && (iFlags & 0x04) /*ENT_NOQUOTES*/ ){ - /* Do not process double quotes */ - jx9_result_string(pCtx, azHtmlEscape[n], -1); - }else{ - jx9_result_string(pCtx, azHtmlEscape[n+1], -1); /* Compute length automatically */ - } - }else{ - /* Append '&' */ - jx9_result_string(pCtx, "&", (int)sizeof(char)); - zIn++; - } - } - return JX9_OK; -} -/* - * int strlen($string) - * return the length of the given string. - * Parameter - * string: The string being measured for length. - * Return - * length of the given string. - */ -static int jx9Builtin_strlen(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int iLen = 0; - if( nArg > 0 ){ - jx9_value_to_string(apArg[0], &iLen); - } - /* String length */ - jx9_result_int(pCtx, iLen); - return JX9_OK; -} -/* - * int strcmp(string $str1, string $str2) - * Perform a binary safe string comparison. - * Parameter - * str1: The first string - * str2: The second string - * Return - * Returns < 0 if str1 is less than str2; > 0 if str1 is greater - * than str2, and 0 if they are equal. - */ -static int jx9Builtin_strcmp(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *z1, *z2; - int n1, n2; - int res; - if( nArg < 2 ){ - res = nArg == 0 ? 0 : 1; - jx9_result_int(pCtx, res); - return JX9_OK; - } - /* Perform the comparison */ - z1 = jx9_value_to_string(apArg[0], &n1); - z2 = jx9_value_to_string(apArg[1], &n2); - res = SyStrncmp(z1, z2, (sxu32)(SXMAX(n1, n2))); - /* Comparison result */ - jx9_result_int(pCtx, res); - return JX9_OK; -} -/* - * int strncmp(string $str1, string $str2, int n) - * Perform a binary safe string comparison of the first n characters. - * Parameter - * str1: The first string - * str2: The second string - * Return - * Returns < 0 if str1 is less than str2; > 0 if str1 is greater - * than str2, and 0 if they are equal. - */ -static int jx9Builtin_strncmp(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *z1, *z2; - int res; - int n; - if( nArg < 3 ){ - /* Perform a standard comparison */ - return jx9Builtin_strcmp(pCtx, nArg, apArg); - } - /* Desired comparison length */ - n = jx9_value_to_int(apArg[2]); - if( n < 0 ){ - /* Invalid length */ - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the comparison */ - z1 = jx9_value_to_string(apArg[0], 0); - z2 = jx9_value_to_string(apArg[1], 0); - res = SyStrncmp(z1, z2, (sxu32)n); - /* Comparison result */ - jx9_result_int(pCtx, res); - return JX9_OK; -} -/* - * int strcasecmp(string $str1, string $str2, int n) - * Perform a binary safe case-insensitive string comparison. - * Parameter - * str1: The first string - * str2: The second string - * Return - * Returns < 0 if str1 is less than str2; > 0 if str1 is greater - * than str2, and 0 if they are equal. - */ -static int jx9Builtin_strcasecmp(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *z1, *z2; - int n1, n2; - int res; - if( nArg < 2 ){ - res = nArg == 0 ? 0 : 1; - jx9_result_int(pCtx, res); - return JX9_OK; - } - /* Perform the comparison */ - z1 = jx9_value_to_string(apArg[0], &n1); - z2 = jx9_value_to_string(apArg[1], &n2); - res = SyStrnicmp(z1, z2, (sxu32)(SXMAX(n1, n2))); - /* Comparison result */ - jx9_result_int(pCtx, res); - return JX9_OK; -} -/* - * int strncasecmp(string $str1, string $str2, int n) - * Perform a binary safe case-insensitive string comparison of the first n characters. - * Parameter - * $str1: The first string - * $str2: The second string - * $len: The length of strings to be used in the comparison. - * Return - * Returns < 0 if str1 is less than str2; > 0 if str1 is greater - * than str2, and 0 if they are equal. - */ -static int jx9Builtin_strncasecmp(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *z1, *z2; - int res; - int n; - if( nArg < 3 ){ - /* Perform a standard comparison */ - return jx9Builtin_strcasecmp(pCtx, nArg, apArg); - } - /* Desired comparison length */ - n = jx9_value_to_int(apArg[2]); - if( n < 0 ){ - /* Invalid length */ - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the comparison */ - z1 = jx9_value_to_string(apArg[0], 0); - z2 = jx9_value_to_string(apArg[1], 0); - res = SyStrnicmp(z1, z2, (sxu32)n); - /* Comparison result */ - jx9_result_int(pCtx, res); - return JX9_OK; -} -/* - * Implode context [i.e: it's private data]. - * A pointer to the following structure is forwarded - * verbatim to the array walker callback defined below. - */ -struct implode_data { - jx9_context *pCtx; /* Call context */ - int bRecursive; /* TRUE if recursive implode [this is a symisc eXtension] */ - const char *zSep; /* Arguments separator if any */ - int nSeplen; /* Separator length */ - int bFirst; /* TRUE if first call */ - int nRecCount; /* Recursion count to avoid infinite loop */ -}; -/* - * Implode walker callback for the [jx9_array_walk()] interface. - * The following routine is invoked for each array entry passed - * to the implode() function. - */ -static int implode_callback(jx9_value *pKey, jx9_value *pValue, void *pUserData) -{ - struct implode_data *pData = (struct implode_data *)pUserData; - const char *zData; - int nLen; - if( pData->bRecursive && jx9_value_is_json_array(pValue) && pData->nRecCount < 32 ){ - if( pData->nSeplen > 0 ){ - if( !pData->bFirst ){ - /* append the separator first */ - jx9_result_string(pData->pCtx, pData->zSep, pData->nSeplen); - }else{ - pData->bFirst = 0; - } - } - /* Recurse */ - pData->bFirst = 1; - pData->nRecCount++; - jx9HashmapWalk((jx9_hashmap *)pValue->x.pOther, implode_callback, pData); - pData->nRecCount--; - return JX9_OK; - } - /* Extract the string representation of the entry value */ - zData = jx9_value_to_string(pValue, &nLen); - if( nLen > 0 ){ - if( pData->nSeplen > 0 ){ - if( !pData->bFirst ){ - /* append the separator first */ - jx9_result_string(pData->pCtx, pData->zSep, pData->nSeplen); - }else{ - pData->bFirst = 0; - } - } - jx9_result_string(pData->pCtx, zData, nLen); - }else{ - SXUNUSED(pKey); /* cc warning */ - } - return JX9_OK; -} -/* - * string implode(string $glue, array $pieces, ...) - * string implode(array $pieces, ...) - * Join array elements with a string. - * $glue - * Defaults to an empty string. This is not the preferred usage of implode() as glue - * would be the second parameter and thus, the bad prototype would be used. - * $pieces - * The array of strings to implode. - * Return - * Returns a string containing a string representation of all the array elements in the same - * order, with the glue string between each element. - */ -static int jx9Builtin_implode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - struct implode_data imp_data; - int i = 1; - if( nArg < 1 ){ - /* Missing argument, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Prepare the implode context */ - imp_data.pCtx = pCtx; - imp_data.bRecursive = 0; - imp_data.bFirst = 1; - imp_data.nRecCount = 0; - if( !jx9_value_is_json_array(apArg[0]) ){ - imp_data.zSep = jx9_value_to_string(apArg[0], &imp_data.nSeplen); - }else{ - imp_data.zSep = 0; - imp_data.nSeplen = 0; - i = 0; - } - jx9_result_string(pCtx, "", 0); /* Set an empty stirng */ - /* Start the 'join' process */ - while( i < nArg ){ - if( jx9_value_is_json_array(apArg[i]) ){ - /* Iterate throw array entries */ - jx9_array_walk(apArg[i], implode_callback, &imp_data); - }else{ - const char *zData; - int nLen; - /* Extract the string representation of the jx9 value */ - zData = jx9_value_to_string(apArg[i], &nLen); - if( nLen > 0 ){ - if( imp_data.nSeplen > 0 ){ - if( !imp_data.bFirst ){ - /* append the separator first */ - jx9_result_string(pCtx, imp_data.zSep, imp_data.nSeplen); - }else{ - imp_data.bFirst = 0; - } - } - jx9_result_string(pCtx, zData, nLen); - } - } - i++; - } - return JX9_OK; -} -/* - * string implode_recursive(string $glue, array $pieces, ...) - * Purpose - * Same as implode() but recurse on arrays. - * Example: - * $a = array('usr', array('home', 'dean')); - * print implode_recursive("/", $a); - * Will output - * usr/home/dean. - * While the standard implode would produce. - * usr/Array. - * Parameter - * Refer to implode(). - * Return - * Refer to implode(). - */ -static int jx9Builtin_implode_recursive(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - struct implode_data imp_data; - int i = 1; - if( nArg < 1 ){ - /* Missing argument, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Prepare the implode context */ - imp_data.pCtx = pCtx; - imp_data.bRecursive = 1; - imp_data.bFirst = 1; - imp_data.nRecCount = 0; - if( !jx9_value_is_json_array(apArg[0]) ){ - imp_data.zSep = jx9_value_to_string(apArg[0], &imp_data.nSeplen); - }else{ - imp_data.zSep = 0; - imp_data.nSeplen = 0; - i = 0; - } - jx9_result_string(pCtx, "", 0); /* Set an empty stirng */ - /* Start the 'join' process */ - while( i < nArg ){ - if( jx9_value_is_json_array(apArg[i]) ){ - /* Iterate throw array entries */ - jx9_array_walk(apArg[i], implode_callback, &imp_data); - }else{ - const char *zData; - int nLen; - /* Extract the string representation of the jx9 value */ - zData = jx9_value_to_string(apArg[i], &nLen); - if( nLen > 0 ){ - if( imp_data.nSeplen > 0 ){ - if( !imp_data.bFirst ){ - /* append the separator first */ - jx9_result_string(pCtx, imp_data.zSep, imp_data.nSeplen); - }else{ - imp_data.bFirst = 0; - } - } - jx9_result_string(pCtx, zData, nLen); - } - } - i++; - } - return JX9_OK; -} -/* - * array explode(string $delimiter, string $string[, int $limit ]) - * Returns an array of strings, each of which is a substring of string - * formed by splitting it on boundaries formed by the string delimiter. - * Parameters - * $delimiter - * The boundary string. - * $string - * The input string. - * $limit - * If limit is set and positive, the returned array will contain a maximum - * of limit elements with the last element containing the rest of string. - * If the limit parameter is negative, all fields except the last -limit are returned. - * If the limit parameter is zero, then this is treated as 1. - * Returns - * Returns an array of strings created by splitting the string parameter - * on boundaries formed by the delimiter. - * If delimiter is an empty string (""), explode() will return FALSE. - * If delimiter contains a value that is not contained in string and a negative - * limit is used, then an empty array will be returned, otherwise an array containing string - * will be returned. - * NOTE: - * Negative limit is not supported. - */ -static int jx9Builtin_explode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zDelim, *zString, *zCur, *zEnd; - int nDelim, nStrlen, iLimit; - jx9_value *pArray; - jx9_value *pValue; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the delimiter */ - zDelim = jx9_value_to_string(apArg[0], &nDelim); - if( nDelim < 1 ){ - /* Empty delimiter, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the string */ - zString = jx9_value_to_string(apArg[1], &nStrlen); - if( nStrlen < 1 ){ - /* Empty delimiter, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the end of the string */ - zEnd = &zString[nStrlen]; - /* Create the array */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - /* Out of memory, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Set a defualt limit */ - iLimit = SXI32_HIGH; - if( nArg > 2 ){ - iLimit = jx9_value_to_int(apArg[2]); - if( iLimit < 0 ){ - iLimit = -iLimit; - } - if( iLimit == 0 ){ - iLimit = 1; - } - iLimit--; - } - /* Start exploding */ - for(;;){ - if( zString >= zEnd ){ - /* No more entry to process */ - break; - } - rc = SyBlobSearch(zString, (sxu32)(zEnd-zString), zDelim, nDelim, &nOfft); - if( rc != SXRET_OK || iLimit <= (int)jx9_array_count(pArray) ){ - /* Limit reached, insert the rest of the string and break */ - if( zEnd > zString ){ - jx9_value_string(pValue, zString, (int)(zEnd-zString)); - jx9_array_add_elem(pArray, 0/* Automatic index assign*/, pValue); - } - break; - } - /* Point to the desired offset */ - zCur = &zString[nOfft]; - if( zCur > zString ){ - /* Perform the store operation */ - jx9_value_string(pValue, zString, (int)(zCur-zString)); - jx9_array_add_elem(pArray, 0/* Automatic index assign*/, pValue); - } - /* Point beyond the delimiter */ - zString = &zCur[nDelim]; - /* Reset the cursor */ - jx9_value_reset_string_cursor(pValue); - } - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - /* NOTE that every allocated jx9_value will be automatically - * released as soon we return from this foregin function. - */ - return JX9_OK; -} -/* - * string trim(string $str[, string $charlist ]) - * Strip whitespace (or other characters) from the beginning and end of a string. - * Parameters - * $str - * The string that will be trimmed. - * $charlist - * Optionally, the stripped characters can also be specified using the charlist parameter. - * Simply list all characters that you want to be stripped. - * With .. you can specify a range of characters. - * Returns. - * Thr processed string. - */ -static int jx9Builtin_trim(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Start the trim process */ - if( nArg < 2 ){ - SyString sStr; - /* Remove white spaces and NUL bytes */ - SyStringInitFromBuf(&sStr, zString, nLen); - SyStringFullTrimSafe(&sStr); - jx9_result_string(pCtx, sStr.zString, (int)sStr.nByte); - }else{ - /* Char list */ - const char *zList; - int nListlen; - zList = jx9_value_to_string(apArg[1], &nListlen); - if( nListlen < 1 ){ - /* Return the string unchanged */ - jx9_result_string(pCtx, zString, nLen); - }else{ - const char *zEnd = &zString[nLen]; - const char *zCur = zString; - const char *zPtr; - int i; - /* Left trim */ - for(;;){ - if( zCur >= zEnd ){ - break; - } - zPtr = zCur; - for( i = 0 ; i < nListlen ; i++ ){ - if( zCur < zEnd && zCur[0] == zList[i] ){ - zCur++; - } - } - if( zCur == zPtr ){ - /* No match, break immediately */ - break; - } - } - /* Right trim */ - zEnd--; - for(;;){ - if( zEnd <= zCur ){ - break; - } - zPtr = zEnd; - for( i = 0 ; i < nListlen ; i++ ){ - if( zEnd > zCur && zEnd[0] == zList[i] ){ - zEnd--; - } - } - if( zEnd == zPtr ){ - break; - } - } - if( zCur >= zEnd ){ - /* Return the empty string */ - jx9_result_string(pCtx, "", 0); - }else{ - zEnd++; - jx9_result_string(pCtx, zCur, (int)(zEnd-zCur)); - } - } - } - return JX9_OK; -} -/* - * string rtrim(string $str[, string $charlist ]) - * Strip whitespace (or other characters) from the end of a string. - * Parameters - * $str - * The string that will be trimmed. - * $charlist - * Optionally, the stripped characters can also be specified using the charlist parameter. - * Simply list all characters that you want to be stripped. - * With .. you can specify a range of characters. - * Returns. - * Thr processed string. - */ -static int jx9Builtin_rtrim(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Start the trim process */ - if( nArg < 2 ){ - SyString sStr; - /* Remove white spaces and NUL bytes*/ - SyStringInitFromBuf(&sStr, zString, nLen); - SyStringRightTrimSafe(&sStr); - jx9_result_string(pCtx, sStr.zString, (int)sStr.nByte); - }else{ - /* Char list */ - const char *zList; - int nListlen; - zList = jx9_value_to_string(apArg[1], &nListlen); - if( nListlen < 1 ){ - /* Return the string unchanged */ - jx9_result_string(pCtx, zString, nLen); - }else{ - const char *zEnd = &zString[nLen - 1]; - const char *zCur = zString; - const char *zPtr; - int i; - /* Right trim */ - for(;;){ - if( zEnd <= zCur ){ - break; - } - zPtr = zEnd; - for( i = 0 ; i < nListlen ; i++ ){ - if( zEnd > zCur && zEnd[0] == zList[i] ){ - zEnd--; - } - } - if( zEnd == zPtr ){ - break; - } - } - if( zEnd <= zCur ){ - /* Return the empty string */ - jx9_result_string(pCtx, "", 0); - }else{ - zEnd++; - jx9_result_string(pCtx, zCur, (int)(zEnd-zCur)); - } - } - } - return JX9_OK; -} -/* - * string ltrim(string $str[, string $charlist ]) - * Strip whitespace (or other characters) from the beginning and end of a string. - * Parameters - * $str - * The string that will be trimmed. - * $charlist - * Optionally, the stripped characters can also be specified using the charlist parameter. - * Simply list all characters that you want to be stripped. - * With .. you can specify a range of characters. - * Returns. - * The processed string. - */ -static int jx9Builtin_ltrim(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Start the trim process */ - if( nArg < 2 ){ - SyString sStr; - /* Remove white spaces and NUL byte */ - SyStringInitFromBuf(&sStr, zString, nLen); - SyStringLeftTrimSafe(&sStr); - jx9_result_string(pCtx, sStr.zString, (int)sStr.nByte); - }else{ - /* Char list */ - const char *zList; - int nListlen; - zList = jx9_value_to_string(apArg[1], &nListlen); - if( nListlen < 1 ){ - /* Return the string unchanged */ - jx9_result_string(pCtx, zString, nLen); - }else{ - const char *zEnd = &zString[nLen]; - const char *zCur = zString; - const char *zPtr; - int i; - /* Left trim */ - for(;;){ - if( zCur >= zEnd ){ - break; - } - zPtr = zCur; - for( i = 0 ; i < nListlen ; i++ ){ - if( zCur < zEnd && zCur[0] == zList[i] ){ - zCur++; - } - } - if( zCur == zPtr ){ - /* No match, break immediately */ - break; - } - } - if( zCur >= zEnd ){ - /* Return the empty string */ - jx9_result_string(pCtx, "", 0); - }else{ - jx9_result_string(pCtx, zCur, (int)(zEnd-zCur)); - } - } - } - return JX9_OK; -} -/* - * string strtolower(string $str) - * Make a string lowercase. - * Parameters - * $str - * The input string. - * Returns. - * The lowercased string. - */ -static int jx9Builtin_strtolower(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zCur, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Perform the requested operation */ - zEnd = &zString[nLen]; - for(;;){ - if( zString >= zEnd ){ - /* No more input, break immediately */ - break; - } - if( (unsigned char)zString[0] >= 0xc0 ){ - /* UTF-8 stream, output verbatim */ - zCur = zString; - zString++; - while( zString < zEnd && ((unsigned char)zString[0] & 0xc0) == 0x80){ - zString++; - } - /* Append UTF-8 stream */ - jx9_result_string(pCtx, zCur, (int)(zString-zCur)); - }else{ - int c = zString[0]; - if( SyisUpper(c) ){ - c = SyToLower(zString[0]); - } - /* Append character */ - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - /* Advance the cursor */ - zString++; - } - } - return JX9_OK; -} -/* - * string strtolower(string $str) - * Make a string uppercase. - * Parameters - * $str - * The input string. - * Returns. - * The uppercased string. - */ -static int jx9Builtin_strtoupper(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zCur, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Perform the requested operation */ - zEnd = &zString[nLen]; - for(;;){ - if( zString >= zEnd ){ - /* No more input, break immediately */ - break; - } - if( (unsigned char)zString[0] >= 0xc0 ){ - /* UTF-8 stream, output verbatim */ - zCur = zString; - zString++; - while( zString < zEnd && ((unsigned char)zString[0] & 0xc0) == 0x80){ - zString++; - } - /* Append UTF-8 stream */ - jx9_result_string(pCtx, zCur, (int)(zString-zCur)); - }else{ - int c = zString[0]; - if( SyisLower(c) ){ - c = SyToUpper(zString[0]); - } - /* Append character */ - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - /* Advance the cursor */ - zString++; - } - } - return JX9_OK; -} -/* - * int ord(string $string) - * Returns the ASCII value of the first character of string. - * Parameters - * $str - * The input string. - * Returns. - * The ASCII value as an integer. - */ -static int jx9Builtin_ord(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString; - int nLen, c; - if( nArg < 1 ){ - /* Missing arguments, return -1 */ - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return -1 */ - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Extract the ASCII value of the first character */ - c = zString[0]; - /* Return that value */ - jx9_result_int(pCtx, c); - return JX9_OK; -} -/* - * string chr(int $ascii) - * Returns a one-character string containing the character specified by ascii. - * Parameters - * $ascii - * The ascii code. - * Returns. - * The specified character. - */ -static int jx9Builtin_chr(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int c; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the ASCII value */ - c = jx9_value_to_int(apArg[0]); - /* Return the specified character */ - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - return JX9_OK; -} -/* - * Binary to hex consumer callback. - * This callback is the default consumer used by the hash functions - * [i.e: bin2hex(), md5(), sha1(), md5_file() ... ] defined below. - */ -static int HashConsumer(const void *pData, unsigned int nLen, void *pUserData) -{ - /* Append hex chunk verbatim */ - jx9_result_string((jx9_context *)pUserData, (const char *)pData, (int)nLen); - return SXRET_OK; -} -/* - * string bin2hex(string $str) - * Convert binary data into hexadecimal representation. - * Parameters - * $str - * The input string. - * Returns. - * Returns the hexadecimal representation of the given string. - */ -static int jx9Builtin_bin2hex(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Perform the requested operation */ - SyBinToHexConsumer((const void *)zString, (sxu32)nLen, HashConsumer, pCtx); - return JX9_OK; -} -/* Search callback signature */ -typedef sxi32 (*ProcStringMatch)(const void *, sxu32, const void *, sxu32, sxu32 *); -/* - * Case-insensitive pattern match. - * Brute force is the default search method used here. - * This is due to the fact that brute-forcing works quite - * well for short/medium texts on modern hardware. - */ -static sxi32 iPatternMatch(const void *pText, sxu32 nLen, const void *pPattern, sxu32 iPatLen, sxu32 *pOfft) -{ - const char *zpIn = (const char *)pPattern; - const char *zIn = (const char *)pText; - const char *zpEnd = &zpIn[iPatLen]; - const char *zEnd = &zIn[nLen]; - const char *zPtr, *zPtr2; - int c, d; - if( iPatLen > nLen ){ - /* Don't bother processing */ - return SXERR_NOTFOUND; - } - for(;;){ - if( zIn >= zEnd ){ - break; - } - c = SyToLower(zIn[0]); - d = SyToLower(zpIn[0]); - if( c == d ){ - zPtr = &zIn[1]; - zPtr2 = &zpIn[1]; - for(;;){ - if( zPtr2 >= zpEnd ){ - /* Pattern found */ - if( pOfft ){ *pOfft = (sxu32)(zIn-(const char *)pText); } - return SXRET_OK; - } - if( zPtr >= zEnd ){ - break; - } - c = SyToLower(zPtr[0]); - d = SyToLower(zPtr2[0]); - if( c != d ){ - break; - } - zPtr++; zPtr2++; - } - } - zIn++; - } - /* Pattern not found */ - return SXERR_NOTFOUND; -} -/* - * string strstr(string $haystack, string $needle[, bool $before_needle = false ]) - * Find the first occurrence of a string. - * Parameters - * $haystack - * The input string. - * $needle - * Search pattern (must be a string). - * $before_needle - * If TRUE, strstr() returns the part of the haystack before the first occurrence - * of the needle (excluding the needle). - * Return - * Returns the portion of string, or FALSE if needle is not found. - */ -static int jx9Builtin_strstr(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - ProcStringMatch xPatternMatch = SyBlobSearch; /* Case-sensitive pattern match */ - const char *zBlob, *zPattern; - int nLen, nPatLen; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the needle and the haystack */ - zBlob = jx9_value_to_string(apArg[0], &nLen); - zPattern = jx9_value_to_string(apArg[1], &nPatLen); - nOfft = 0; /* cc warning */ - if( nLen > 0 && nPatLen > 0 ){ - int before = 0; - /* Perform the lookup */ - rc = xPatternMatch(zBlob, (sxu32)nLen, zPattern, (sxu32)nPatLen, &nOfft); - if( rc != SXRET_OK ){ - /* Pattern not found, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return the portion of the string */ - if( nArg > 2 ){ - before = jx9_value_to_int(apArg[2]); - } - if( before ){ - jx9_result_string(pCtx, zBlob, (int)(&zBlob[nOfft]-zBlob)); - }else{ - jx9_result_string(pCtx, &zBlob[nOfft], (int)(&zBlob[nLen]-&zBlob[nOfft])); - } - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * string stristr(string $haystack, string $needle[, bool $before_needle = false ]) - * Case-insensitive strstr(). - * Parameters - * $haystack - * The input string. - * $needle - * Search pattern (must be a string). - * $before_needle - * If TRUE, strstr() returns the part of the haystack before the first occurrence - * of the needle (excluding the needle). - * Return - * Returns the portion of string, or FALSE if needle is not found. - */ -static int jx9Builtin_stristr(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - ProcStringMatch xPatternMatch = iPatternMatch; /* Case-insensitive pattern match */ - const char *zBlob, *zPattern; - int nLen, nPatLen; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the needle and the haystack */ - zBlob = jx9_value_to_string(apArg[0], &nLen); - zPattern = jx9_value_to_string(apArg[1], &nPatLen); - nOfft = 0; /* cc warning */ - if( nLen > 0 && nPatLen > 0 ){ - int before = 0; - /* Perform the lookup */ - rc = xPatternMatch(zBlob, (sxu32)nLen, zPattern, (sxu32)nPatLen, &nOfft); - if( rc != SXRET_OK ){ - /* Pattern not found, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return the portion of the string */ - if( nArg > 2 ){ - before = jx9_value_to_int(apArg[2]); - } - if( before ){ - jx9_result_string(pCtx, zBlob, (int)(&zBlob[nOfft]-zBlob)); - }else{ - jx9_result_string(pCtx, &zBlob[nOfft], (int)(&zBlob[nLen]-&zBlob[nOfft])); - } - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * int strpos(string $haystack, string $needle [, int $offset = 0 ] ) - * Returns the numeric position of the first occurrence of needle in the haystack string. - * Parameters - * $haystack - * The input string. - * $needle - * Search pattern (must be a string). - * $offset - * This optional offset parameter allows you to specify which character in haystack - * to start searching. The position returned is still relative to the beginning - * of haystack. - * Return - * Returns the position as an integer.If needle is not found, strpos() will return FALSE. - */ -static int jx9Builtin_strpos(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - ProcStringMatch xPatternMatch = SyBlobSearch; /* Case-sensitive pattern match */ - const char *zBlob, *zPattern; - int nLen, nPatLen, nStart; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the needle and the haystack */ - zBlob = jx9_value_to_string(apArg[0], &nLen); - zPattern = jx9_value_to_string(apArg[1], &nPatLen); - nOfft = 0; /* cc warning */ - nStart = 0; - /* Peek the starting offset if available */ - if( nArg > 2 ){ - nStart = jx9_value_to_int(apArg[2]); - if( nStart < 0 ){ - nStart = -nStart; - } - if( nStart >= nLen ){ - /* Invalid offset */ - nStart = 0; - }else{ - zBlob += nStart; - nLen -= nStart; - } - } - if( nLen > 0 && nPatLen > 0 ){ - /* Perform the lookup */ - rc = xPatternMatch(zBlob, (sxu32)nLen, zPattern, (sxu32)nPatLen, &nOfft); - if( rc != SXRET_OK ){ - /* Pattern not found, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return the pattern position */ - jx9_result_int64(pCtx, (jx9_int64)(nOfft+nStart)); - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * int stripos(string $haystack, string $needle [, int $offset = 0 ] ) - * Case-insensitive strpos. - * Parameters - * $haystack - * The input string. - * $needle - * Search pattern (must be a string). - * $offset - * This optional offset parameter allows you to specify which character in haystack - * to start searching. The position returned is still relative to the beginning - * of haystack. - * Return - * Returns the position as an integer.If needle is not found, strpos() will return FALSE. - */ -static int jx9Builtin_stripos(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - ProcStringMatch xPatternMatch = iPatternMatch; /* Case-insensitive pattern match */ - const char *zBlob, *zPattern; - int nLen, nPatLen, nStart; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the needle and the haystack */ - zBlob = jx9_value_to_string(apArg[0], &nLen); - zPattern = jx9_value_to_string(apArg[1], &nPatLen); - nOfft = 0; /* cc warning */ - nStart = 0; - /* Peek the starting offset if available */ - if( nArg > 2 ){ - nStart = jx9_value_to_int(apArg[2]); - if( nStart < 0 ){ - nStart = -nStart; - } - if( nStart >= nLen ){ - /* Invalid offset */ - nStart = 0; - }else{ - zBlob += nStart; - nLen -= nStart; - } - } - if( nLen > 0 && nPatLen > 0 ){ - /* Perform the lookup */ - rc = xPatternMatch(zBlob, (sxu32)nLen, zPattern, (sxu32)nPatLen, &nOfft); - if( rc != SXRET_OK ){ - /* Pattern not found, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return the pattern position */ - jx9_result_int64(pCtx, (jx9_int64)(nOfft+nStart)); - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * int strrpos(string $haystack, string $needle [, int $offset = 0 ] ) - * Find the numeric position of the last occurrence of needle in the haystack string. - * Parameters - * $haystack - * The input string. - * $needle - * Search pattern (must be a string). - * $offset - * If specified, search will start this number of characters counted from the beginning - * of the string. If the value is negative, search will instead start from that many - * characters from the end of the string, searching backwards. - * Return - * Returns the position as an integer.If needle is not found, strrpos() will return FALSE. - */ -static int jx9Builtin_strrpos(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zStart, *zBlob, *zPattern, *zPtr, *zEnd; - ProcStringMatch xPatternMatch = SyBlobSearch; /* Case-sensitive pattern match */ - int nLen, nPatLen; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the needle and the haystack */ - zBlob = jx9_value_to_string(apArg[0], &nLen); - zPattern = jx9_value_to_string(apArg[1], &nPatLen); - /* Point to the end of the pattern */ - zPtr = &zBlob[nLen - 1]; - zEnd = &zBlob[nLen]; - /* Save the starting posistion */ - zStart = zBlob; - nOfft = 0; /* cc warning */ - /* Peek the starting offset if available */ - if( nArg > 2 ){ - int nStart; - nStart = jx9_value_to_int(apArg[2]); - if( nStart < 0 ){ - nStart = -nStart; - if( nStart >= nLen ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - }else{ - nLen -= nStart; - zPtr = &zBlob[nLen - 1]; - zEnd = &zBlob[nLen]; - } - }else{ - if( nStart >= nLen ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - }else{ - zBlob += nStart; - nLen -= nStart; - } - } - } - if( nLen > 0 && nPatLen > 0 ){ - /* Perform the lookup */ - for(;;){ - if( zBlob >= zPtr ){ - break; - } - rc = xPatternMatch((const void *)zPtr, (sxu32)(zEnd-zPtr), (const void *)zPattern, (sxu32)nPatLen, &nOfft); - if( rc == SXRET_OK ){ - /* Pattern found, return it's position */ - jx9_result_int64(pCtx, (jx9_int64)(&zPtr[nOfft] - zStart)); - return JX9_OK; - } - zPtr--; - } - /* Pattern not found, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * int strripos(string $haystack, string $needle [, int $offset = 0 ] ) - * Case-insensitive strrpos. - * Parameters - * $haystack - * The input string. - * $needle - * Search pattern (must be a string). - * $offset - * If specified, search will start this number of characters counted from the beginning - * of the string. If the value is negative, search will instead start from that many - * characters from the end of the string, searching backwards. - * Return - * Returns the position as an integer.If needle is not found, strrpos() will return FALSE. - */ -static int jx9Builtin_strripos(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zStart, *zBlob, *zPattern, *zPtr, *zEnd; - ProcStringMatch xPatternMatch = iPatternMatch; /* Case-insensitive pattern match */ - int nLen, nPatLen; - sxu32 nOfft; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the needle and the haystack */ - zBlob = jx9_value_to_string(apArg[0], &nLen); - zPattern = jx9_value_to_string(apArg[1], &nPatLen); - /* Point to the end of the pattern */ - zPtr = &zBlob[nLen - 1]; - zEnd = &zBlob[nLen]; - /* Save the starting posistion */ - zStart = zBlob; - nOfft = 0; /* cc warning */ - /* Peek the starting offset if available */ - if( nArg > 2 ){ - int nStart; - nStart = jx9_value_to_int(apArg[2]); - if( nStart < 0 ){ - nStart = -nStart; - if( nStart >= nLen ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - }else{ - nLen -= nStart; - zPtr = &zBlob[nLen - 1]; - zEnd = &zBlob[nLen]; - } - }else{ - if( nStart >= nLen ){ - /* Invalid offset */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - }else{ - zBlob += nStart; - nLen -= nStart; - } - } - } - if( nLen > 0 && nPatLen > 0 ){ - /* Perform the lookup */ - for(;;){ - if( zBlob >= zPtr ){ - break; - } - rc = xPatternMatch((const void *)zPtr, (sxu32)(zEnd-zPtr), (const void *)zPattern, (sxu32)nPatLen, &nOfft); - if( rc == SXRET_OK ){ - /* Pattern found, return it's position */ - jx9_result_int64(pCtx, (jx9_int64)(&zPtr[nOfft] - zStart)); - return JX9_OK; - } - zPtr--; - } - /* Pattern not found, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * int strrchr(string $haystack, mixed $needle) - * Find the last occurrence of a character in a string. - * Parameters - * $haystack - * The input string. - * $needle - * If needle contains more than one character, only the first is used. - * This behavior is different from that of strstr(). - * If needle is not a string, it is converted to an integer and applied - * as the ordinal value of a character. - * Return - * This function returns the portion of string, or FALSE if needle is not found. - */ -static int jx9Builtin_strrchr(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zBlob; - int nLen, c; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the haystack */ - zBlob = jx9_value_to_string(apArg[0], &nLen); - c = 0; /* cc warning */ - if( nLen > 0 ){ - sxu32 nOfft; - sxi32 rc; - if( jx9_value_is_string(apArg[1]) ){ - const char *zPattern; - zPattern = jx9_value_to_string(apArg[1], 0); /* Never fail, so there is no need to check - * for NULL pointer. - */ - c = zPattern[0]; - }else{ - /* Int cast */ - c = jx9_value_to_int(apArg[1]); - } - /* Perform the lookup */ - rc = SyByteFind2(zBlob, (sxu32)nLen, c, &nOfft); - if( rc != SXRET_OK ){ - /* No such entry, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return the string portion */ - jx9_result_string(pCtx, &zBlob[nOfft], (int)(&zBlob[nLen]-&zBlob[nOfft])); - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * string strrev(string $string) - * Reverse a string. - * Parameters - * $string - * String to be reversed. - * Return - * The reversed string. - */ -static int jx9Builtin_strrev(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn, *zEnd; - int nLen, c; - if( nArg < 1 ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string Return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Perform the requested operation */ - zEnd = &zIn[nLen - 1]; - for(;;){ - if( zEnd < zIn ){ - /* No more input to process */ - break; - } - /* Append current character */ - c = zEnd[0]; - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - zEnd--; - } - return JX9_OK; -} -/* - * string str_repeat(string $input, int $multiplier) - * Returns input repeated multiplier times. - * Parameters - * $string - * String to be repeated. - * $multiplier - * Number of time the input string should be repeated. - * multiplier has to be greater than or equal to 0. If the multiplier is set - * to 0, the function will return an empty string. - * Return - * The repeated string. - */ -static int jx9Builtin_str_repeat(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn; - int nLen, nMul; - int rc; - if( nArg < 2 ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string.Return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the multiplier */ - nMul = jx9_value_to_int(apArg[1]); - if( nMul < 1 ){ - /* Return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( nMul < 1 ){ - break; - } - /* Append the copy */ - rc = jx9_result_string(pCtx, zIn, nLen); - if( rc != JX9_OK ){ - /* Out of memory, break immediately */ - break; - } - nMul--; - } - return JX9_OK; -} -/* - * string nl2br(string $string[, bool $is_xhtml = true ]) - * Inserts HTML line breaks before all newlines in a string. - * Parameters - * $string - * The input string. - * $is_xhtml - * Whenever to use XHTML compatible line breaks or not. - * Return - * The processed string. - */ -static int jx9Builtin_nl2br(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn, *zCur, *zEnd; - int is_xhtml = 0; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - if( nArg > 1 ){ - is_xhtml = jx9_value_to_bool(apArg[1]); - } - zEnd = &zIn[nLen]; - /* Perform the requested operation */ - for(;;){ - zCur = zIn; - /* Delimit the string */ - while( zIn < zEnd && (zIn[0] != '\n'&& zIn[0] != '\r') ){ - zIn++; - } - if( zCur < zIn ){ - /* Output chunk verbatim */ - jx9_result_string(pCtx, zCur, (int)(zIn-zCur)); - } - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - /* Output the HTML line break */ - if( is_xhtml ){ - jx9_result_string(pCtx, "
", (int)sizeof("
")-1); - }else{ - jx9_result_string(pCtx, "
", (int)sizeof("
")-1); - } - zCur = zIn; - /* Append trailing line */ - while( zIn < zEnd && (zIn[0] == '\n' || zIn[0] == '\r') ){ - zIn++; - } - if( zCur < zIn ){ - /* Output chunk verbatim */ - jx9_result_string(pCtx, zCur, (int)(zIn-zCur)); - } - } - return JX9_OK; -} -/* - * Format a given string and invoke the given callback on each processed chunk. - * According to the JX9 reference manual. - * The format string is composed of zero or more directives: ordinary characters - * (excluding %) that are copied directly to the result, and conversion - * specifications, each of which results in fetching its own parameter. - * This applies to both sprintf() and printf(). - * Each conversion specification consists of a percent sign (%), followed by one - * or more of these elements, in order: - * An optional sign specifier that forces a sign (- or +) to be used on a number. - * By default, only the - sign is used on a number if it's negative. This specifier forces - * positive numbers to have the + sign attached as well. - * An optional padding specifier that says what character will be used for padding - * the results to the right string size. This may be a space character or a 0 (zero character). - * The default is to pad with spaces. An alternate padding character can be specified by prefixing - * it with a single quote ('). See the examples below. - * An optional alignment specifier that says if the result should be left-justified or right-justified. - * The default is right-justified; a - character here will make it left-justified. - * An optional number, a width specifier that says how many characters (minimum) this conversion - * should result in. - * An optional precision specifier in the form of a period (`.') followed by an optional decimal - * digit string that says how many decimal digits should be displayed for floating-point numbers. - * When using this specifier on a string, it acts as a cutoff point, setting a maximum character - * limit to the string. - * A type specifier that says what type the argument data should be treated as. Possible types: - * % - a literal percent character. No argument is required. - * b - the argument is treated as an integer, and presented as a binary number. - * c - the argument is treated as an integer, and presented as the character with that ASCII value. - * d - the argument is treated as an integer, and presented as a (signed) decimal number. - * e - the argument is treated as scientific notation (e.g. 1.2e+2). The precision specifier stands - * for the number of digits after the decimal point. - * E - like %e but uses uppercase letter (e.g. 1.2E+2). - * u - the argument is treated as an integer, and presented as an unsigned decimal number. - * f - the argument is treated as a float, and presented as a floating-point number (locale aware). - * F - the argument is treated as a float, and presented as a floating-point number (non-locale aware). - * g - shorter of %e and %f. - * G - shorter of %E and %f. - * o - the argument is treated as an integer, and presented as an octal number. - * s - the argument is treated as and presented as a string. - * x - the argument is treated as an integer and presented as a hexadecimal number (with lowercase letters). - * X - the argument is treated as an integer and presented as a hexadecimal number (with uppercase letters). - */ -/* - * This implementation is based on the one found in the SQLite3 source tree. - */ -#define JX9_FMT_BUFSIZ 1024 /* Conversion buffer size */ -/* -** Conversion types fall into various categories as defined by the -** following enumeration. -*/ -#define JX9_FMT_RADIX 1 /* Integer types.%d, %x, %o, and so forth */ -#define JX9_FMT_FLOAT 2 /* Floating point.%f */ -#define JX9_FMT_EXP 3 /* Exponentional notation.%e and %E */ -#define JX9_FMT_GENERIC 4 /* Floating or exponential, depending on exponent.%g */ -#define JX9_FMT_SIZE 5 /* Total number of characters processed so far.%n */ -#define JX9_FMT_STRING 6 /* Strings.%s */ -#define JX9_FMT_PERCENT 7 /* Percent symbol.%% */ -#define JX9_FMT_CHARX 8 /* Characters.%c */ -#define JX9_FMT_ERROR 9 /* Used to indicate no such conversion type */ -/* -** Allowed values for jx9_fmt_info.flags -*/ -#define JX9_FMT_FLAG_SIGNED 0x01 -#define JX9_FMT_FLAG_UNSIGNED 0x02 -/* -** Each builtin conversion character (ex: the 'd' in "%d") is described -** by an instance of the following structure -*/ -typedef struct jx9_fmt_info jx9_fmt_info; -struct jx9_fmt_info -{ - char fmttype; /* The format field code letter [i.e: 'd', 's', 'x'] */ - sxu8 base; /* The base for radix conversion */ - int flags; /* One or more of JX9_FMT_FLAG_ constants below */ - sxu8 type; /* Conversion paradigm */ - char *charset; /* The character set for conversion */ - char *prefix; /* Prefix on non-zero values in alt format */ -}; -#ifndef JX9_OMIT_FLOATING_POINT -/* -** "*val" is a double such that 0.1 <= *val < 10.0 -** Return the ascii code for the leading digit of *val, then -** multiply "*val" by 10.0 to renormalize. -** -** Example: -** input: *val = 3.14159 -** output: *val = 1.4159 function return = '3' -** -** The counter *cnt is incremented each time. After counter exceeds -** 16 (the number of significant digits in a 64-bit float) '0' is -** always returned. -*/ -static int vxGetdigit(sxlongreal *val, int *cnt) -{ - sxlongreal d; - int digit; - - if( (*cnt)++ >= 16 ){ - return '0'; - } - digit = (int)*val; - d = digit; - *val = (*val - d)*10.0; - return digit + '0' ; -} -#endif /* JX9_OMIT_FLOATING_POINT */ -/* - * The following table is searched linearly, so it is good to put the most frequently - * used conversion types first. - */ -static const jx9_fmt_info aFmt[] = { - { 'd', 10, JX9_FMT_FLAG_SIGNED, JX9_FMT_RADIX, "0123456789", 0 }, - { 's', 0, 0, JX9_FMT_STRING, 0, 0 }, - { 'c', 0, 0, JX9_FMT_CHARX, 0, 0 }, - { 'x', 16, 0, JX9_FMT_RADIX, "0123456789abcdef", "x0" }, - { 'X', 16, 0, JX9_FMT_RADIX, "0123456789ABCDEF", "X0" }, - { 'b', 2, 0, JX9_FMT_RADIX, "01", "b0"}, - { 'o', 8, 0, JX9_FMT_RADIX, "01234567", "0" }, - { 'u', 10, 0, JX9_FMT_RADIX, "0123456789", 0 }, - { 'f', 0, JX9_FMT_FLAG_SIGNED, JX9_FMT_FLOAT, 0, 0 }, - { 'F', 0, JX9_FMT_FLAG_SIGNED, JX9_FMT_FLOAT, 0, 0 }, - { 'e', 0, JX9_FMT_FLAG_SIGNED, JX9_FMT_EXP, "e", 0 }, - { 'E', 0, JX9_FMT_FLAG_SIGNED, JX9_FMT_EXP, "E", 0 }, - { 'g', 0, JX9_FMT_FLAG_SIGNED, JX9_FMT_GENERIC, "e", 0 }, - { 'G', 0, JX9_FMT_FLAG_SIGNED, JX9_FMT_GENERIC, "E", 0 }, - { '%', 0, 0, JX9_FMT_PERCENT, 0, 0 } -}; -/* - * Format a given string. - * The root program. All variations call this core. - * INPUTS: - * xConsumer This is a pointer to a function taking four arguments - * 1. A pointer to the call context. - * 2. A pointer to the list of characters to be output - * (Note, this list is NOT null terminated.) - * 3. An integer number of characters to be output. - * (Note: This number might be zero.) - * 4. Upper layer private data. - * zIn This is the format string, as in the usual print. - * apArg This is a pointer to a list of arguments. - */ -JX9_PRIVATE sxi32 jx9InputFormat( - int (*xConsumer)(jx9_context *, const char *, int, void *), /* Format consumer */ - jx9_context *pCtx, /* call context */ - const char *zIn, /* Format string */ - int nByte, /* Format string length */ - int nArg, /* Total argument of the given arguments */ - jx9_value **apArg, /* User arguments */ - void *pUserData, /* Last argument to xConsumer() */ - int vf /* TRUE if called from vfprintf, vsprintf context */ - ) -{ - char spaces[] = " "; -#define etSPACESIZE ((int)sizeof(spaces)-1) - const char *zCur, *zEnd = &zIn[nByte]; - char *zBuf, zWorker[JX9_FMT_BUFSIZ]; /* Working buffer */ - const jx9_fmt_info *pInfo; /* Pointer to the appropriate info structure */ - int flag_alternateform; /* True if "#" flag is present */ - int flag_leftjustify; /* True if "-" flag is present */ - int flag_blanksign; /* True if " " flag is present */ - int flag_plussign; /* True if "+" flag is present */ - int flag_zeropad; /* True if field width constant starts with zero */ - jx9_value *pArg; /* Current processed argument */ - jx9_int64 iVal; - int precision; /* Precision of the current field */ - char *zExtra; - int c, rc, n; - int length; /* Length of the field */ - int prefix; - sxu8 xtype; /* Conversion paradigm */ - int width; /* Width of the current field */ - int idx; - n = (vf == TRUE) ? 0 : 1; -#define NEXT_ARG ( n < nArg ? apArg[n++] : 0 ) - /* Start the format process */ - for(;;){ - zCur = zIn; - while( zIn < zEnd && zIn[0] != '%' ){ - zIn++; - } - if( zCur < zIn ){ - /* Consume chunk verbatim */ - rc = xConsumer(pCtx, zCur, (int)(zIn-zCur), pUserData); - if( rc == SXERR_ABORT ){ - /* Callback request an operation abort */ - break; - } - } - if( zIn >= zEnd ){ - /* No more input to process, break immediately */ - break; - } - /* Find out what flags are present */ - flag_leftjustify = flag_plussign = flag_blanksign = - flag_alternateform = flag_zeropad = 0; - zIn++; /* Jump the precent sign */ - do{ - c = zIn[0]; - switch( c ){ - case '-': flag_leftjustify = 1; c = 0; break; - case '+': flag_plussign = 1; c = 0; break; - case ' ': flag_blanksign = 1; c = 0; break; - case '#': flag_alternateform = 1; c = 0; break; - case '0': flag_zeropad = 1; c = 0; break; - case '\'': - zIn++; - if( zIn < zEnd ){ - /* An alternate padding character can be specified by prefixing it with a single quote (') */ - c = zIn[0]; - for(idx = 0 ; idx < etSPACESIZE ; ++idx ){ - spaces[idx] = (char)c; - } - c = 0; - } - break; - default: break; - } - }while( c==0 && (zIn++ < zEnd) ); - /* Get the field width */ - width = 0; - while( zIn < zEnd && ( zIn[0] >='0' && zIn[0] <='9') ){ - width = width*10 + (zIn[0] - '0'); - zIn++; - } - if( zIn < zEnd && zIn[0] == '$' ){ - /* Position specifer */ - if( width > 0 ){ - n = width; - if( vf && n > 0 ){ - n--; - } - } - zIn++; - width = 0; - if( zIn < zEnd && zIn[0] == '0' ){ - flag_zeropad = 1; - zIn++; - } - while( zIn < zEnd && ( zIn[0] >='0' && zIn[0] <='9') ){ - width = width*10 + (zIn[0] - '0'); - zIn++; - } - } - if( width > JX9_FMT_BUFSIZ-10 ){ - width = JX9_FMT_BUFSIZ-10; - } - /* Get the precision */ - precision = -1; - if( zIn < zEnd && zIn[0] == '.' ){ - precision = 0; - zIn++; - while( zIn < zEnd && ( zIn[0] >='0' && zIn[0] <='9') ){ - precision = precision*10 + (zIn[0] - '0'); - zIn++; - } - } - if( zIn >= zEnd ){ - /* No more input */ - break; - } - /* Fetch the info entry for the field */ - pInfo = 0; - xtype = JX9_FMT_ERROR; - c = zIn[0]; - zIn++; /* Jump the format specifer */ - for(idx=0; idx< (int)SX_ARRAYSIZE(aFmt); idx++){ - if( c==aFmt[idx].fmttype ){ - pInfo = &aFmt[idx]; - xtype = pInfo->type; - break; - } - } - zBuf = zWorker; /* Point to the working buffer */ - length = 0; - zExtra = 0; - /* - ** At this point, variables are initialized as follows: - ** - ** flag_alternateform TRUE if a '#' is present. - ** flag_plussign TRUE if a '+' is present. - ** flag_leftjustify TRUE if a '-' is present or if the - ** field width was negative. - ** flag_zeropad TRUE if the width began with 0. - ** the conversion character. - ** flag_blanksign TRUE if a ' ' is present. - ** width The specified field width. This is - ** always non-negative. Zero is the default. - ** precision The specified precision. The default - ** is -1. - */ - switch(xtype){ - case JX9_FMT_PERCENT: - /* A literal percent character */ - zWorker[0] = '%'; - length = (int)sizeof(char); - break; - case JX9_FMT_CHARX: - /* The argument is treated as an integer, and presented as the character - * with that ASCII value - */ - pArg = NEXT_ARG; - if( pArg == 0 ){ - c = 0; - }else{ - c = jx9_value_to_int(pArg); - } - /* NUL byte is an acceptable value */ - zWorker[0] = (char)c; - length = (int)sizeof(char); - break; - case JX9_FMT_STRING: - /* the argument is treated as and presented as a string */ - pArg = NEXT_ARG; - if( pArg == 0 ){ - length = 0; - }else{ - zBuf = (char *)jx9_value_to_string(pArg, &length); - } - if( length < 1 ){ - zBuf = " "; - length = (int)sizeof(char); - } - if( precision>=0 && precisionJX9_FMT_BUFSIZ-40 ){ - precision = JX9_FMT_BUFSIZ-40; - } -#if 1 - /* For the format %#x, the value zero is printed "0" not "0x0". - ** I think this is stupid.*/ - if( iVal==0 ) flag_alternateform = 0; -#else - /* More sensible: turn off the prefix for octal (to prevent "00"), - ** but leave the prefix for hex.*/ - if( iVal==0 && pInfo->base==8 ) flag_alternateform = 0; -#endif - if( pInfo->flags & JX9_FMT_FLAG_SIGNED ){ - if( iVal<0 ){ - iVal = -iVal; - /* Ticket 1433-003 */ - if( iVal < 0 ){ - /* Overflow */ - iVal= 0x7FFFFFFFFFFFFFFF; - } - prefix = '-'; - }else if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; - }else{ - if( iVal<0 ){ - iVal = -iVal; - /* Ticket 1433-003 */ - if( iVal < 0 ){ - /* Overflow */ - iVal= 0x7FFFFFFFFFFFFFFF; - } - } - prefix = 0; - } - if( flag_zeropad && precisioncharset; - base = pInfo->base; - do{ /* Convert to ascii */ - *(--zBuf) = cset[iVal%base]; - iVal = iVal/base; - }while( iVal>0 ); - } - length = &zWorker[JX9_FMT_BUFSIZ-1]-zBuf; - for(idx=precision-length; idx>0; idx--){ - *(--zBuf) = '0'; /* Zero pad */ - } - if( prefix ) *(--zBuf) = (char)prefix; /* Add sign */ - if( flag_alternateform && pInfo->prefix ){ /* Add "0" or "0x" */ - char *pre, x; - pre = pInfo->prefix; - if( *zBuf!=pre[0] ){ - for(pre=pInfo->prefix; (x=(*pre))!=0; pre++) *(--zBuf) = x; - } - } - length = &zWorker[JX9_FMT_BUFSIZ-1]-zBuf; - break; - case JX9_FMT_FLOAT: - case JX9_FMT_EXP: - case JX9_FMT_GENERIC:{ -#ifndef JX9_OMIT_FLOATING_POINT - long double realvalue; - int exp; /* exponent of real numbers */ - double rounder; /* Used for rounding floating point values */ - int flag_dp; /* True if decimal point should be shown */ - int flag_rtz; /* True if trailing zeros should be removed */ - int flag_exp; /* True to force display of the exponent */ - int nsd; /* Number of significant digits returned */ - pArg = NEXT_ARG; - if( pArg == 0 ){ - realvalue = 0; - }else{ - realvalue = jx9_value_to_double(pArg); - } - if( precision<0 ) precision = 6; /* Set default precision */ - if( precision>JX9_FMT_BUFSIZ-40) precision = JX9_FMT_BUFSIZ-40; - if( realvalue<0.0 ){ - realvalue = -realvalue; - prefix = '-'; - }else{ - if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; - } - if( pInfo->type==JX9_FMT_GENERIC && precision>0 ) precision--; - rounder = 0.0; -#if 0 - /* Rounding works like BSD when the constant 0.4999 is used.Wierd! */ - for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); -#else - /* It makes more sense to use 0.5 */ - for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1); -#endif - if( pInfo->type==JX9_FMT_FLOAT ) realvalue += rounder; - /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ - exp = 0; - if( realvalue>0.0 ){ - while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } - while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } - while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } - while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } - if( exp>350 || exp<-350 ){ - zBuf = "NaN"; - length = 3; - break; - } - } - zBuf = zWorker; - /* - ** If the field type is etGENERIC, then convert to either etEXP - ** or etFLOAT, as appropriate. - */ - flag_exp = xtype==JX9_FMT_EXP; - if( xtype!=JX9_FMT_FLOAT ){ - realvalue += rounder; - if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } - } - if( xtype==JX9_FMT_GENERIC ){ - flag_rtz = !flag_alternateform; - if( exp<-4 || exp>precision ){ - xtype = JX9_FMT_EXP; - }else{ - precision = precision - exp; - xtype = JX9_FMT_FLOAT; - } - }else{ - flag_rtz = 0; - } - /* - ** The "exp+precision" test causes output to be of type etEXP if - ** the precision is too large to fit in buf[]. - */ - nsd = 0; - if( xtype==JX9_FMT_FLOAT && exp+precision0 || flag_alternateform); - if( prefix ) *(zBuf++) = (char)prefix; /* Sign */ - if( exp<0 ) *(zBuf++) = '0'; /* Digits before "." */ - else for(; exp>=0; exp--) *(zBuf++) = (char)vxGetdigit(&realvalue, &nsd); - if( flag_dp ) *(zBuf++) = '.'; /* The decimal point */ - for(exp++; exp<0 && precision>0; precision--, exp++){ - *(zBuf++) = '0'; - } - while( (precision--)>0 ) *(zBuf++) = (char)vxGetdigit(&realvalue, &nsd); - *(zBuf--) = 0; /* Null terminate */ - if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ - while( zBuf>=zWorker && *zBuf=='0' ) *(zBuf--) = 0; - if( zBuf>=zWorker && *zBuf=='.' ) *(zBuf--) = 0; - } - zBuf++; /* point to next free slot */ - }else{ /* etEXP or etGENERIC */ - flag_dp = (precision>0 || flag_alternateform); - if( prefix ) *(zBuf++) = (char)prefix; /* Sign */ - *(zBuf++) = (char)vxGetdigit(&realvalue, &nsd); /* First digit */ - if( flag_dp ) *(zBuf++) = '.'; /* Decimal point */ - while( (precision--)>0 ) *(zBuf++) = (char)vxGetdigit(&realvalue, &nsd); - zBuf--; /* point to last digit */ - if( flag_rtz && flag_dp ){ /* Remove tail zeros */ - while( zBuf>=zWorker && *zBuf=='0' ) *(zBuf--) = 0; - if( zBuf>=zWorker && *zBuf=='.' ) *(zBuf--) = 0; - } - zBuf++; /* point to next free slot */ - if( exp || flag_exp ){ - *(zBuf++) = pInfo->charset[0]; - if( exp<0 ){ *(zBuf++) = '-'; exp = -exp; } /* sign of exp */ - else { *(zBuf++) = '+'; } - if( exp>=100 ){ - *(zBuf++) = (char)((exp/100)+'0'); /* 100's digit */ - exp %= 100; - } - *(zBuf++) = (char)(exp/10+'0'); /* 10's digit */ - *(zBuf++) = (char)(exp%10+'0'); /* 1's digit */ - } - } - /* The converted number is in buf[] and zero terminated.Output it. - ** Note that the number is in the usual order, not reversed as with - ** integer conversions.*/ - length = (int)(zBuf-zWorker); - zBuf = zWorker; - /* Special case: Add leading zeros if the flag_zeropad flag is - ** set and we are not left justified */ - if( flag_zeropad && !flag_leftjustify && length < width){ - int i; - int nPad = width - length; - for(i=width; i>=nPad; i--){ - zBuf[i] = zBuf[i-nPad]; - } - i = prefix!=0; - while( nPad-- ) zBuf[i++] = '0'; - length = width; - } -#else - zBuf = " "; - length = (int)sizeof(char); -#endif /* JX9_OMIT_FLOATING_POINT */ - break; - } - default: - /* Invalid format specifer */ - zWorker[0] = '?'; - length = (int)sizeof(char); - break; - } - /* - ** The text of the conversion is pointed to by "zBuf" and is - ** "length" characters long.The field width is "width".Do - ** the output. - */ - if( !flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - while( nspace>=etSPACESIZE ){ - rc = xConsumer(pCtx, spaces, etSPACESIZE, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - nspace -= etSPACESIZE; - } - if( nspace>0 ){ - rc = xConsumer(pCtx, spaces, (unsigned int)nspace, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - } - } - } - if( length>0 ){ - rc = xConsumer(pCtx, zBuf, (unsigned int)length, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - } - if( flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - while( nspace>=etSPACESIZE ){ - rc = xConsumer(pCtx, spaces, etSPACESIZE, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - nspace -= etSPACESIZE; - } - if( nspace>0 ){ - rc = xConsumer(pCtx, spaces, (unsigned int)nspace, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - } - } - } - }/* for(;;) */ - return SXRET_OK; -} -/* - * Callback [i.e: Formatted input consumer] of the sprintf function. - */ -static int sprintfConsumer(jx9_context *pCtx, const char *zInput, int nLen, void *pUserData) -{ - /* Consume directly */ - jx9_result_string(pCtx, zInput, nLen); - SXUNUSED(pUserData); /* cc warning */ - return JX9_OK; -} -/* - * string sprintf(string $format[, mixed $args [, mixed $... ]]) - * Return a formatted string. - * Parameters - * $format - * The format string (see block comment above) - * Return - * A string produced according to the formatting string format. - */ -static int jx9Builtin_sprintf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFormat; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Format the string */ - jx9InputFormat(sprintfConsumer, pCtx, zFormat, nLen, nArg, apArg, 0, FALSE); - return JX9_OK; -} -/* - * Callback [i.e: Formatted input consumer] of the printf function. - */ -static int printfConsumer(jx9_context *pCtx, const char *zInput, int nLen, void *pUserData) -{ - jx9_int64 *pCounter = (jx9_int64 *)pUserData; - /* Call the VM output consumer directly */ - jx9_context_output(pCtx, zInput, nLen); - /* Increment counter */ - *pCounter += nLen; - return JX9_OK; -} -/* - * int64 printf(string $format[, mixed $args[, mixed $... ]]) - * Output a formatted string. - * Parameters - * $format - * See sprintf() for a description of format. - * Return - * The length of the outputted string. - */ -static int jx9Builtin_printf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_int64 nCounter = 0; - const char *zFormat; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Format the string */ - jx9InputFormat(printfConsumer, pCtx, zFormat, nLen, nArg, apArg, (void *)&nCounter, FALSE); - /* Return the length of the outputted string */ - jx9_result_int64(pCtx, nCounter); - return JX9_OK; -} -/* - * int vprintf(string $format, array $args) - * Output a formatted string. - * Parameters - * $format - * See sprintf() for a description of format. - * Return - * The length of the outputted string. - */ -static int jx9Builtin_vprintf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_int64 nCounter = 0; - const char *zFormat; - jx9_hashmap *pMap; - SySet sArg; - int nLen, n; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_json_array(apArg[1]) ){ - /* Missing/Invalid arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the hashmap */ - pMap = (jx9_hashmap *)apArg[1]->x.pOther; - /* Extract arguments from the hashmap */ - n = jx9HashmapValuesToSet(pMap, &sArg); - /* Format the string */ - jx9InputFormat(printfConsumer, pCtx, zFormat, nLen, n, (jx9_value **)SySetBasePtr(&sArg), (void *)&nCounter, TRUE); - /* Return the length of the outputted string */ - jx9_result_int64(pCtx, nCounter); - /* Release the container */ - SySetRelease(&sArg); - return JX9_OK; -} -/* - * int vsprintf(string $format, array $args) - * Output a formatted string. - * Parameters - * $format - * See sprintf() for a description of format. - * Return - * A string produced according to the formatting string format. - */ -static int jx9Builtin_vsprintf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFormat; - jx9_hashmap *pMap; - SySet sArg; - int nLen, n; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_json_array(apArg[1]) ){ - /* Missing/Invalid arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Point to hashmap */ - pMap = (jx9_hashmap *)apArg[1]->x.pOther; - /* Extract arguments from the hashmap */ - n = jx9HashmapValuesToSet(pMap, &sArg); - /* Format the string */ - jx9InputFormat(sprintfConsumer, pCtx, zFormat, nLen, n, (jx9_value **)SySetBasePtr(&sArg), 0, TRUE); - /* Release the container */ - SySetRelease(&sArg); - return JX9_OK; -} -/* - * string size_format(int64 $size) - * Return a smart string represenation of the given size [i.e: 64-bit integer] - * Example: - * print size_format(1*1024*1024*1024);// 1GB - * print size_format(512*1024*1024); // 512 MB - * print size_format(file_size(/path/to/my/file_8192)); //8KB - * Parameter - * $size - * Entity size in bytes. - * Return - * Formatted string representation of the given size. - */ -static int jx9Builtin_size_format(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - /*Kilo*/ /*Mega*/ /*Giga*/ /*Tera*/ /*Peta*/ /*Exa*/ /*Zeta*/ - static const char zUnit[] = {"KMGTPEZ"}; - sxi32 nRest, i_32; - jx9_int64 iSize; - int c = -1; /* index in zUnit[] */ - - if( nArg < 1 ){ - /* Missing argument, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the given size */ - iSize = jx9_value_to_int64(apArg[0]); - if( iSize < 100 /* Bytes */ ){ - /* Don't bother formatting, return immediately */ - jx9_result_string(pCtx, "0.1 KB", (int)sizeof("0.1 KB")-1); - return JX9_OK; - } - for(;;){ - nRest = (sxi32)(iSize & 0x3FF); - iSize >>= 10; - c++; - if( (iSize & (~0 ^ 1023)) == 0 ){ - break; - } - } - nRest /= 100; - if( nRest > 9 ){ - nRest = 9; - } - if( iSize > 999 ){ - c++; - nRest = 9; - iSize = 0; - } - i_32 = (sxi32)iSize; - /* Format */ - jx9_result_string_format(pCtx, "%d.%d %cB", i_32, nRest, zUnit[c]); - return JX9_OK; -} -#if !defined(JX9_DISABLE_HASH_FUNC) -/* - * string md5(string $str[, bool $raw_output = false]) - * Calculate the md5 hash of a string. - * Parameter - * $str - * Input string - * $raw_output - * If the optional raw_output is set to TRUE, then the md5 digest - * is instead returned in raw binary format with a length of 16. - * Return - * MD5 Hash as a 32-character hexadecimal string. - */ -static int jx9Builtin_md5(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - unsigned char zDigest[16]; - int raw_output = FALSE; - const void *pIn; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the input string */ - pIn = (const void *)jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - if( nArg > 1 && jx9_value_is_bool(apArg[1])){ - raw_output = jx9_value_to_bool(apArg[1]); - } - /* Compute the MD5 digest */ - SyMD5Compute(pIn, (sxu32)nLen, zDigest); - if( raw_output ){ - /* Output raw digest */ - jx9_result_string(pCtx, (const char *)zDigest, (int)sizeof(zDigest)); - }else{ - /* Perform a binary to hex conversion */ - SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), HashConsumer, pCtx); - } - return JX9_OK; -} -/* - * string sha1(string $str[, bool $raw_output = false]) - * Calculate the sha1 hash of a string. - * Parameter - * $str - * Input string - * $raw_output - * If the optional raw_output is set to TRUE, then the md5 digest - * is instead returned in raw binary format with a length of 16. - * Return - * SHA1 Hash as a 40-character hexadecimal string. - */ -static int jx9Builtin_sha1(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - unsigned char zDigest[20]; - int raw_output = FALSE; - const void *pIn; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the input string */ - pIn = (const void *)jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - if( nArg > 1 && jx9_value_is_bool(apArg[1])){ - raw_output = jx9_value_to_bool(apArg[1]); - } - /* Compute the SHA1 digest */ - SySha1Compute(pIn, (sxu32)nLen, zDigest); - if( raw_output ){ - /* Output raw digest */ - jx9_result_string(pCtx, (const char *)zDigest, (int)sizeof(zDigest)); - }else{ - /* Perform a binary to hex conversion */ - SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), HashConsumer, pCtx); - } - return JX9_OK; -} -/* - * int64 crc32(string $str) - * Calculates the crc32 polynomial of a strin. - * Parameter - * $str - * Input string - * Return - * CRC32 checksum of the given input (64-bit integer). - */ -static int jx9Builtin_crc32(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const void *pIn; - sxu32 nCRC; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the input string */ - pIn = (const void *)jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty string */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Calculate the sum */ - nCRC = SyCrc32(pIn, (sxu32)nLen); - /* Return the CRC32 as 64-bit integer */ - jx9_result_int64(pCtx, (jx9_int64)nCRC^ 0xFFFFFFFF); - return JX9_OK; -} -#endif /* JX9_DISABLE_HASH_FUNC */ -/* - * Parse a CSV string and invoke the supplied callback for each processed xhunk. - */ -JX9_PRIVATE sxi32 jx9ProcessCsv( - const char *zInput, /* Raw input */ - int nByte, /* Input length */ - int delim, /* Delimiter */ - int encl, /* Enclosure */ - int escape, /* Escape character */ - sxi32 (*xConsumer)(const char *, int, void *), /* User callback */ - void *pUserData /* Last argument to xConsumer() */ - ) -{ - const char *zEnd = &zInput[nByte]; - const char *zIn = zInput; - const char *zPtr; - int isEnc; - /* Start processing */ - for(;;){ - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - isEnc = 0; - zPtr = zIn; - /* Find the first delimiter */ - while( zIn < zEnd ){ - if( zIn[0] == delim && !isEnc){ - /* Delimiter found, break imediately */ - break; - }else if( zIn[0] == encl ){ - /* Inside enclosure? */ - isEnc = !isEnc; - }else if( zIn[0] == escape ){ - /* Escape sequence */ - zIn++; - } - /* Advance the cursor */ - zIn++; - } - if( zIn > zPtr ){ - int nByte = (int)(zIn-zPtr); - sxi32 rc; - /* Invoke the supllied callback */ - if( zPtr[0] == encl ){ - zPtr++; - nByte-=2; - } - if( nByte > 0 ){ - rc = xConsumer(zPtr, nByte, pUserData); - if( rc == SXERR_ABORT ){ - /* User callback request an operation abort */ - break; - } - } - } - /* Ignore trailing delimiter */ - while( zIn < zEnd && zIn[0] == delim ){ - zIn++; - } - } - return SXRET_OK; -} -/* - * Default consumer callback for the CSV parsing routine defined above. - * All the processed input is insereted into an array passed as the last - * argument to this callback. - */ -JX9_PRIVATE sxi32 jx9CsvConsumer(const char *zToken, int nTokenLen, void *pUserData) -{ - jx9_value *pArray = (jx9_value *)pUserData; - jx9_value sEntry; - SyString sToken; - /* Insert the token in the given array */ - SyStringInitFromBuf(&sToken, zToken, nTokenLen); - /* Remove trailing and leading white spcaces and null bytes */ - SyStringFullTrimSafe(&sToken); - if( sToken.nByte < 1){ - return SXRET_OK; - } - jx9MemObjInitFromString(pArray->pVm, &sEntry, &sToken); - jx9_array_add_elem(pArray, 0, &sEntry); - jx9MemObjRelease(&sEntry); - return SXRET_OK; -} -/* - * array str_getcsv(string $input[, string $delimiter = ', '[, string $enclosure = '"' [, string $escape='\\']]]) - * Parse a CSV string into an array. - * Parameters - * $input - * The string to parse. - * $delimiter - * Set the field delimiter (one character only). - * $enclosure - * Set the field enclosure character (one character only). - * $escape - * Set the escape character (one character only). Defaults as a backslash (\) - * Return - * An indexed array containing the CSV fields or NULL on failure. - */ -static int jx9Builtin_str_getcsv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zInput, *zPtr; - jx9_value *pArray; - int delim = ','; /* Delimiter */ - int encl = '"' ; /* Enclosure */ - int escape = '\\'; /* Escape character */ - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the raw input */ - zInput = jx9_value_to_string(apArg[0], &nLen); - if( nArg > 1 ){ - int i; - if( jx9_value_is_string(apArg[1]) ){ - /* Extract the delimiter */ - zPtr = jx9_value_to_string(apArg[1], &i); - if( i > 0 ){ - delim = zPtr[0]; - } - } - if( nArg > 2 ){ - if( jx9_value_is_string(apArg[2]) ){ - /* Extract the enclosure */ - zPtr = jx9_value_to_string(apArg[2], &i); - if( i > 0 ){ - encl = zPtr[0]; - } - } - if( nArg > 3 ){ - if( jx9_value_is_string(apArg[3]) ){ - /* Extract the escape character */ - zPtr = jx9_value_to_string(apArg[3], &i); - if( i > 0 ){ - escape = zPtr[0]; - } - } - } - } - } - /* Create our array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_null(pCtx); - return JX9_OK; - } - /* Parse the raw input */ - jx9ProcessCsv(zInput, nLen, delim, encl, escape, jx9CsvConsumer, pArray); - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * Extract a tag name from a raw HTML input and insert it in the given - * container. - * Refer to [strip_tags()]. - */ -static sxi32 AddTag(SySet *pSet, const char *zTag, int nByte) -{ - const char *zEnd = &zTag[nByte]; - const char *zPtr; - SyString sEntry; - /* Strip tags */ - for(;;){ - while( zTag < zEnd && (zTag[0] == '<' || zTag[0] == '/' || zTag[0] == '?' - || zTag[0] == '!' || zTag[0] == '-' || ((unsigned char)zTag[0] < 0xc0 && SyisSpace(zTag[0]))) ){ - zTag++; - } - if( zTag >= zEnd ){ - break; - } - zPtr = zTag; - /* Delimit the tag */ - while(zTag < zEnd ){ - if( (unsigned char)zTag[0] >= 0xc0 ){ - /* UTF-8 stream */ - zTag++; - SX_JMP_UTF8(zTag, zEnd); - }else if( !SyisAlphaNum(zTag[0]) ){ - break; - }else{ - zTag++; - } - } - if( zTag > zPtr ){ - /* Perform the insertion */ - SyStringInitFromBuf(&sEntry, zPtr, (int)(zTag-zPtr)); - SyStringFullTrim(&sEntry); - SySetPut(pSet, (const void *)&sEntry); - } - /* Jump the trailing '>' */ - zTag++; - } - return SXRET_OK; -} -/* - * Check if the given HTML tag name is present in the given container. - * Return SXRET_OK if present.SXERR_NOTFOUND otherwise. - * Refer to [strip_tags()]. - */ -static sxi32 FindTag(SySet *pSet, const char *zTag, int nByte) -{ - if( SySetUsed(pSet) > 0 ){ - const char *zCur, *zEnd = &zTag[nByte]; - SyString sTag; - while( zTag < zEnd && (zTag[0] == '<' || zTag[0] == '/' || zTag[0] == '?' || - ((unsigned char)zTag[0] < 0xc0 && SyisSpace(zTag[0]))) ){ - zTag++; - } - /* Delimit the tag */ - zCur = zTag; - while(zTag < zEnd ){ - if( (unsigned char)zTag[0] >= 0xc0 ){ - /* UTF-8 stream */ - zTag++; - SX_JMP_UTF8(zTag, zEnd); - }else if( !SyisAlphaNum(zTag[0]) ){ - break; - }else{ - zTag++; - } - } - SyStringInitFromBuf(&sTag, zCur, zTag-zCur); - /* Trim leading white spaces and null bytes */ - SyStringLeftTrimSafe(&sTag); - if( sTag.nByte > 0 ){ - SyString *aEntry, *pEntry; - sxi32 rc; - sxu32 n; - /* Perform the lookup */ - aEntry = (SyString *)SySetBasePtr(pSet); - for( n = 0 ; n < SySetUsed(pSet) ; ++n ){ - pEntry = &aEntry[n]; - /* Do the comparison */ - rc = SyStringCmp(pEntry, &sTag, SyStrnicmp); - if( !rc ){ - return SXRET_OK; - } - } - } - } - /* No such tag */ - return SXERR_NOTFOUND; -} -/* - * This function tries to return a string [i.e: in the call context result buffer] - * with all NUL bytes, HTML and JX9 tags stripped from a given string. - * Refer to [strip_tags()]. - */ -JX9_PRIVATE sxi32 jx9StripTagsFromString(jx9_context *pCtx, const char *zIn, int nByte, const char *zTaglist, int nTaglen) -{ - const char *zEnd = &zIn[nByte]; - const char *zPtr, *zTag; - SySet sSet; - /* initialize the set of allowed tags */ - SySetInit(&sSet, &pCtx->pVm->sAllocator, sizeof(SyString)); - if( nTaglen > 0 ){ - /* Set of allowed tags */ - AddTag(&sSet, zTaglist, nTaglen); - } - /* Set the empty string */ - jx9_result_string(pCtx, "", 0); - /* Start processing */ - for(;;){ - if(zIn >= zEnd){ - /* No more input to process */ - break; - } - zPtr = zIn; - /* Find a tag */ - while( zIn < zEnd && zIn[0] != '<' && zIn[0] != 0 /* NUL byte */ ){ - zIn++; - } - if( zIn > zPtr ){ - /* Consume raw input */ - jx9_result_string(pCtx, zPtr, (int)(zIn-zPtr)); - } - /* Ignore trailing null bytes */ - while( zIn < zEnd && zIn[0] == 0 ){ - zIn++; - } - if(zIn >= zEnd){ - /* No more input to process */ - break; - } - if( zIn[0] == '<' ){ - sxi32 rc; - zTag = zIn++; - /* Delimit the tag */ - while( zIn < zEnd && zIn[0] != '>' ){ - zIn++; - } - if( zIn < zEnd ){ - zIn++; /* Ignore the trailing closing tag */ - } - /* Query the set */ - rc = FindTag(&sSet, zTag, (int)(zIn-zTag)); - if( rc == SXRET_OK ){ - /* Keep the tag */ - jx9_result_string(pCtx, zTag, (int)(zIn-zTag)); - } - } - } - /* Cleanup */ - SySetRelease(&sSet); - return SXRET_OK; -} -/* - * string strip_tags(string $str[, string $allowable_tags]) - * Strip HTML and JX9 tags from a string. - * Parameters - * $str - * The input string. - * $allowable_tags - * You can use the optional second parameter to specify tags which should not be stripped. - * Return - * Returns the stripped string. - */ -static int jx9Builtin_strip_tags(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zTaglist = 0; - const char *zString; - int nTaglen = 0; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Point to the raw string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nArg > 1 && jx9_value_is_string(apArg[1]) ){ - /* Allowed tag */ - zTaglist = jx9_value_to_string(apArg[1], &nTaglen); - } - /* Process input */ - jx9StripTagsFromString(pCtx, zString, nLen, zTaglist, nTaglen); - return JX9_OK; -} -/* - * array str_split(string $string[, int $split_length = 1 ]) - * Convert a string to an array. - * Parameters - * $str - * The input string. - * $split_length - * Maximum length of the chunk. - * Return - * If the optional split_length parameter is specified, the returned array - * will be broken down into chunks with each being split_length in length, otherwise - * each chunk will be one character in length. FALSE is returned if split_length is less than 1. - * If the split_length length exceeds the length of string, the entire string is returned - * as the first (and only) array element. - */ -static int jx9Builtin_str_split(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zEnd; - jx9_value *pArray, *pValue; - int split_len; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target string */ - zString = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Nothing to process, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - split_len = (int)sizeof(char); - if( nArg > 1 ){ - /* Split length */ - split_len = jx9_value_to_int(apArg[1]); - if( split_len < 1 ){ - /* Invalid length, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( split_len > nLen ){ - split_len = nLen; - } - } - /* Create the array and the scalar value */ - pArray = jx9_context_new_array(pCtx); - /*Chunk value */ - pValue = jx9_context_new_scalar(pCtx); - if( pValue == 0 || pArray == 0 ){ - /* Return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the end of the string */ - zEnd = &zString[nLen]; - /* Perform the requested operation */ - for(;;){ - int nMax; - if( zString >= zEnd ){ - /* No more input to process */ - break; - } - nMax = (int)(zEnd-zString); - if( nMax < split_len ){ - split_len = nMax; - } - /* Copy the current chunk */ - jx9_value_string(pValue, zString, split_len); - /* Insert it */ - jx9_array_add_elem(pArray, 0, pValue); /* Will make it's own copy */ - /* reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - /* Update position */ - zString += split_len; - } - /* - * Return the array. - * Don't worry about freeing memory, everything will be automatically released - * upon we return from this function. - */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * Tokenize a raw string and extract the first non-space token. - * Refer to [strspn()]. - */ -static sxi32 ExtractNonSpaceToken(const char **pzIn, const char *zEnd, SyString *pOut) -{ - const char *zIn = *pzIn; - const char *zPtr; - /* Ignore leading white spaces */ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ - zIn++; - } - if( zIn >= zEnd ){ - /* End of input */ - return SXERR_EOF; - } - zPtr = zIn; - /* Extract the token */ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && !SyisSpace(zIn[0]) ){ - zIn++; - } - SyStringInitFromBuf(pOut, zPtr, zIn-zPtr); - /* Synchronize pointers */ - *pzIn = zIn; - /* Return to the caller */ - return SXRET_OK; -} -/* - * Check if the given string contains only characters from the given mask. - * return the longest match. - * Refer to [strspn()]. - */ -static int LongestStringMask(const char *zString, int nLen, const char *zMask, int nMaskLen) -{ - const char *zEnd = &zString[nLen]; - const char *zIn = zString; - int i, c; - for(;;){ - if( zString >= zEnd ){ - break; - } - /* Extract current character */ - c = zString[0]; - /* Perform the lookup */ - for( i = 0 ; i < nMaskLen ; i++ ){ - if( c == zMask[i] ){ - /* Character found */ - break; - } - } - if( i >= nMaskLen ){ - /* Character not in the current mask, break immediately */ - break; - } - /* Advance cursor */ - zString++; - } - /* Longest match */ - return (int)(zString-zIn); -} -/* - * Do the reverse operation of the previous function [i.e: LongestStringMask()]. - * Refer to [strcspn()]. - */ -static int LongestStringMask2(const char *zString, int nLen, const char *zMask, int nMaskLen) -{ - const char *zEnd = &zString[nLen]; - const char *zIn = zString; - int i, c; - for(;;){ - if( zString >= zEnd ){ - break; - } - /* Extract current character */ - c = zString[0]; - /* Perform the lookup */ - for( i = 0 ; i < nMaskLen ; i++ ){ - if( c == zMask[i] ){ - break; - } - } - if( i < nMaskLen ){ - /* Character in the current mask, break immediately */ - break; - } - /* Advance cursor */ - zString++; - } - /* Longest match */ - return (int)(zString-zIn); -} -/* - * int strspn(string $str, string $mask[, int $start[, int $length]]) - * Finds the length of the initial segment of a string consisting entirely - * of characters contained within a given mask. - * Parameters - * $str - * The input string. - * $mask - * The list of allowable characters. - * $start - * The position in subject to start searching. - * If start is given and is non-negative, then strspn() will begin examining - * subject at the start'th position. For instance, in the string 'abcdef', the character - * at position 0 is 'a', the character at position 2 is 'c', and so forth. - * If start is given and is negative, then strspn() will begin examining subject at the - * start'th position from the end of subject. - * $length - * The length of the segment from subject to examine. - * If length is given and is non-negative, then subject will be examined for length - * characters after the starting position. - * If lengthis given and is negative, then subject will be examined from the starting - * position up to length characters from the end of subject. - * Return - * Returns the length of the initial segment of subject which consists entirely of characters - * in mask. - */ -static int jx9Builtin_strspn(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zMask, *zEnd; - int iMasklen, iLen; - SyString sToken; - int iCount = 0; - int rc; - if( nArg < 2 ){ - /* Missing agruments, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &iLen); - /* Extract the mask */ - zMask = jx9_value_to_string(apArg[1], &iMasklen); - if( iLen < 1 || iMasklen < 1 ){ - /* Nothing to process, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - if( nArg > 2 ){ - int nOfft; - /* Extract the offset */ - nOfft = jx9_value_to_int(apArg[2]); - if( nOfft < 0 ){ - const char *zBase = &zString[iLen + nOfft]; - if( zBase > zString ){ - iLen = (int)(&zString[iLen]-zBase); - zString = zBase; - }else{ - /* Invalid offset */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - }else{ - if( nOfft >= iLen ){ - /* Invalid offset */ - jx9_result_int(pCtx, 0); - return JX9_OK; - }else{ - /* Update offset */ - zString += nOfft; - iLen -= nOfft; - } - } - if( nArg > 3 ){ - int iUserlen; - /* Extract the desired length */ - iUserlen = jx9_value_to_int(apArg[3]); - if( iUserlen > 0 && iUserlen < iLen ){ - iLen = iUserlen; - } - } - } - /* Point to the end of the string */ - zEnd = &zString[iLen]; - /* Extract the first non-space token */ - rc = ExtractNonSpaceToken(&zString, zEnd, &sToken); - if( rc == SXRET_OK && sToken.nByte > 0 ){ - /* Compare against the current mask */ - iCount = LongestStringMask(sToken.zString, (int)sToken.nByte, zMask, iMasklen); - } - /* Longest match */ - jx9_result_int(pCtx, iCount); - return JX9_OK; -} -/* - * int strcspn(string $str, string $mask[, int $start[, int $length]]) - * Find length of initial segment not matching mask. - * Parameters - * $str - * The input string. - * $mask - * The list of not allowed characters. - * $start - * The position in subject to start searching. - * If start is given and is non-negative, then strspn() will begin examining - * subject at the start'th position. For instance, in the string 'abcdef', the character - * at position 0 is 'a', the character at position 2 is 'c', and so forth. - * If start is given and is negative, then strspn() will begin examining subject at the - * start'th position from the end of subject. - * $length - * The length of the segment from subject to examine. - * If length is given and is non-negative, then subject will be examined for length - * characters after the starting position. - * If lengthis given and is negative, then subject will be examined from the starting - * position up to length characters from the end of subject. - * Return - * Returns the length of the segment as an integer. - */ -static int jx9Builtin_strcspn(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zMask, *zEnd; - int iMasklen, iLen; - SyString sToken; - int iCount = 0; - int rc; - if( nArg < 2 ){ - /* Missing agruments, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zString = jx9_value_to_string(apArg[0], &iLen); - /* Extract the mask */ - zMask = jx9_value_to_string(apArg[1], &iMasklen); - if( iLen < 1 ){ - /* Nothing to process, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - if( iMasklen < 1 ){ - /* No given mask, return the string length */ - jx9_result_int(pCtx, iLen); - return JX9_OK; - } - if( nArg > 2 ){ - int nOfft; - /* Extract the offset */ - nOfft = jx9_value_to_int(apArg[2]); - if( nOfft < 0 ){ - const char *zBase = &zString[iLen + nOfft]; - if( zBase > zString ){ - iLen = (int)(&zString[iLen]-zBase); - zString = zBase; - }else{ - /* Invalid offset */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - }else{ - if( nOfft >= iLen ){ - /* Invalid offset */ - jx9_result_int(pCtx, 0); - return JX9_OK; - }else{ - /* Update offset */ - zString += nOfft; - iLen -= nOfft; - } - } - if( nArg > 3 ){ - int iUserlen; - /* Extract the desired length */ - iUserlen = jx9_value_to_int(apArg[3]); - if( iUserlen > 0 && iUserlen < iLen ){ - iLen = iUserlen; - } - } - } - /* Point to the end of the string */ - zEnd = &zString[iLen]; - /* Extract the first non-space token */ - rc = ExtractNonSpaceToken(&zString, zEnd, &sToken); - if( rc == SXRET_OK && sToken.nByte > 0 ){ - /* Compare against the current mask */ - iCount = LongestStringMask2(sToken.zString, (int)sToken.nByte, zMask, iMasklen); - } - /* Longest match */ - jx9_result_int(pCtx, iCount); - return JX9_OK; -} -/* - * string strpbrk(string $haystack, string $char_list) - * Search a string for any of a set of characters. - * Parameters - * $haystack - * The string where char_list is looked for. - * $char_list - * This parameter is case sensitive. - * Return - * Returns a string starting from the character found, or FALSE if it is not found. - */ -static int jx9Builtin_strpbrk(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zList, *zEnd; - int iLen, iListLen, i, c; - sxu32 nOfft, nMax; - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the haystack and the char list */ - zString = jx9_value_to_string(apArg[0], &iLen); - zList = jx9_value_to_string(apArg[1], &iListLen); - if( iLen < 1 ){ - /* Nothing to process, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the end of the string */ - zEnd = &zString[iLen]; - nOfft = nMax = SXU32_HIGH; - /* perform the requested operation */ - for( i = 0 ; i < iListLen ; i++ ){ - c = zList[i]; - rc = SyByteFind(zString, (sxu32)iLen, c, &nMax); - if( rc == SXRET_OK ){ - if( nMax < nOfft ){ - nOfft = nMax; - } - } - } - if( nOfft == SXU32_HIGH ){ - /* No such substring, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the substring */ - jx9_result_string(pCtx, &zString[nOfft], (int)(zEnd-&zString[nOfft])); - } - return JX9_OK; -} -/* - * string soundex(string $str) - * Calculate the soundex key of a string. - * Parameters - * $str - * The input string. - * Return - * Returns the soundex key as a string. - * Note: - * This implementation is based on the one found in the SQLite3 - * source tree. - */ -static int jx9Builtin_soundex(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn; - char zResult[8]; - int i, j; - static const unsigned char iCode[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 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, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, - 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, - 0, 0, 1, 2, 3, 0, 1, 2, 0, 0, 2, 2, 4, 5, 5, 0, - 1, 2, 6, 2, 3, 0, 1, 0, 2, 0, 2, 0, 0, 0, 0, 0, - }; - if( nArg < 1 ){ - /* Missing arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - zIn = (unsigned char *)jx9_value_to_string(apArg[0], 0); - for(i=0; zIn[i] && zIn[i] < 0xc0 && !SyisAlpha(zIn[i]); i++){} - if( zIn[i] ){ - unsigned char prevcode = iCode[zIn[i]&0x7f]; - zResult[0] = (char)SyToUpper(zIn[i]); - for(j=1; j<4 && zIn[i]; i++){ - int code = iCode[zIn[i]&0x7f]; - if( code>0 ){ - if( code!=prevcode ){ - prevcode = (unsigned char)code; - zResult[j++] = (char)code + '0'; - } - }else{ - prevcode = 0; - } - } - while( j<4 ){ - zResult[j++] = '0'; - } - jx9_result_string(pCtx, zResult, 4); - }else{ - jx9_result_string(pCtx, "?000", 4); - } - return JX9_OK; -} -/* - * string wordwrap(string $str[, int $width = 75[, string $break = "\n"]]) - * Wraps a string to a given number of characters. - * Parameters - * $str - * The input string. - * $width - * The column width. - * $break - * The line is broken using the optional break parameter. - * Return - * Returns the given string wrapped at the specified column. - */ -static int jx9Builtin_wordwrap(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn, *zEnd, *zBreak; - int iLen, iBreaklen, iChunk; - if( nArg < 1 ){ - /* Missing arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the input string */ - zIn = jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Nothing to process, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Chunk length */ - iChunk = 75; - iBreaklen = 0; - zBreak = ""; /* cc warning */ - if( nArg > 1 ){ - iChunk = jx9_value_to_int(apArg[1]); - if( iChunk < 1 ){ - iChunk = 75; - } - if( nArg > 2 ){ - zBreak = jx9_value_to_string(apArg[2], &iBreaklen); - } - } - if( iBreaklen < 1 ){ - /* Set a default column break */ -#ifdef __WINNT__ - zBreak = "\r\n"; - iBreaklen = (int)sizeof("\r\n")-1; -#else - zBreak = "\n"; - iBreaklen = (int)sizeof(char); -#endif - } - /* Perform the requested operation */ - zEnd = &zIn[iLen]; - for(;;){ - int nMax; - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - nMax = (int)(zEnd-zIn); - if( iChunk > nMax ){ - iChunk = nMax; - } - /* Append the column first */ - jx9_result_string(pCtx, zIn, iChunk); /* Will make it's own copy */ - /* Advance the cursor */ - zIn += iChunk; - if( zIn < zEnd ){ - /* Append the line break */ - jx9_result_string(pCtx, zBreak, iBreaklen); - } - } - return JX9_OK; -} -/* - * Check if the given character is a member of the given mask. - * Return TRUE on success. FALSE otherwise. - * Refer to [strtok()]. - */ -static int CheckMask(int c, const char *zMask, int nMasklen, int *pOfft) -{ - int i; - for( i = 0 ; i < nMasklen ; ++i ){ - if( c == zMask[i] ){ - if( pOfft ){ - *pOfft = i; - } - return TRUE; - } - } - return FALSE; -} -/* - * Extract a single token from the input stream. - * Refer to [strtok()]. - */ -static sxi32 ExtractToken(const char **pzIn, const char *zEnd, const char *zMask, int nMasklen, SyString *pOut) -{ - const char *zIn = *pzIn; - const char *zPtr; - /* Ignore leading delimiter */ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && CheckMask(zIn[0], zMask, nMasklen, 0) ){ - zIn++; - } - if( zIn >= zEnd ){ - /* End of input */ - return SXERR_EOF; - } - zPtr = zIn; - /* Extract the token */ - while( zIn < zEnd ){ - if( (unsigned char)zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - zIn++; - SX_JMP_UTF8(zIn, zEnd); - }else{ - if( CheckMask(zIn[0], zMask, nMasklen, 0) ){ - break; - } - zIn++; - } - } - SyStringInitFromBuf(pOut, zPtr, zIn-zPtr); - /* Update the cursor */ - *pzIn = zIn; - /* Return to the caller */ - return SXRET_OK; -} -/* strtok auxiliary private data */ -typedef struct strtok_aux_data strtok_aux_data; -struct strtok_aux_data -{ - const char *zDup; /* Complete duplicate of the input */ - const char *zIn; /* Current input stream */ - const char *zEnd; /* End of input */ -}; -/* - * string strtok(string $str, string $token) - * string strtok(string $token) - * strtok() splits a string (str) into smaller strings (tokens), with each token - * being delimited by any character from token. That is, if you have a string like - * "This is an example string" you could tokenize this string into its individual - * words by using the space character as the token. - * Note that only the first call to strtok uses the string argument. Every subsequent - * call to strtok only needs the token to use, as it keeps track of where it is in - * the current string. To start over, or to tokenize a new string you simply call strtok - * with the string argument again to initialize it. Note that you may put multiple tokens - * in the token parameter. The string will be tokenized when any one of the characters in - * the argument are found. - * Parameters - * $str - * The string being split up into smaller strings (tokens). - * $token - * The delimiter used when splitting up str. - * Return - * Current token or FALSE on EOF. - */ -static int jx9Builtin_strtok(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - strtok_aux_data *pAux; - const char *zMask; - SyString sToken; - int nMasklen; - sxi32 rc; - if( nArg < 2 ){ - /* Extract top aux data */ - pAux = (strtok_aux_data *)jx9_context_peek_aux_data(pCtx); - if( pAux == 0 ){ - /* No aux data, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nMasklen = 0; - zMask = ""; /* cc warning */ - if( nArg > 0 ){ - /* Extract the mask */ - zMask = jx9_value_to_string(apArg[0], &nMasklen); - } - if( nMasklen < 1 ){ - /* Invalid mask, return FALSE */ - jx9_context_free_chunk(pCtx, (void *)pAux->zDup); - jx9_context_free_chunk(pCtx, pAux); - (void)jx9_context_pop_aux_data(pCtx); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the token */ - rc = ExtractToken(&pAux->zIn, pAux->zEnd, zMask, nMasklen, &sToken); - if( rc != SXRET_OK ){ - /* EOF , discard the aux data */ - jx9_context_free_chunk(pCtx, (void *)pAux->zDup); - jx9_context_free_chunk(pCtx, pAux); - (void)jx9_context_pop_aux_data(pCtx); - jx9_result_bool(pCtx, 0); - }else{ - /* Return the extracted token */ - jx9_result_string(pCtx, sToken.zString, (int)sToken.nByte); - } - }else{ - const char *zInput, *zCur; - char *zDup; - int nLen; - /* Extract the raw input */ - zCur = zInput = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Empty input, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the mask */ - zMask = jx9_value_to_string(apArg[1], &nMasklen); - if( nMasklen < 1 ){ - /* Set a default mask */ -#define TOK_MASK " \n\t\r\f" - zMask = TOK_MASK; - nMasklen = (int)sizeof(TOK_MASK) - 1; -#undef TOK_MASK - } - /* Extract a single token */ - rc = ExtractToken(&zInput, &zInput[nLen], zMask, nMasklen, &sToken); - if( rc != SXRET_OK ){ - /* Empty input */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - }else{ - /* Return the extracted token */ - jx9_result_string(pCtx, sToken.zString, (int)sToken.nByte); - } - /* Create our auxilliary data and copy the input */ - pAux = (strtok_aux_data *)jx9_context_alloc_chunk(pCtx, sizeof(strtok_aux_data), TRUE, FALSE); - if( pAux ){ - nLen -= (int)(zInput-zCur); - if( nLen < 1 ){ - jx9_context_free_chunk(pCtx, pAux); - return JX9_OK; - } - /* Duplicate input */ - zDup = (char *)jx9_context_alloc_chunk(pCtx, (unsigned int)(nLen+1), TRUE, FALSE); - if( zDup ){ - SyMemcpy(zInput, zDup, (sxu32)nLen); - /* Register the aux data */ - pAux->zDup = pAux->zIn = zDup; - pAux->zEnd = &zDup[nLen]; - jx9_context_push_aux_data(pCtx, pAux); - } - } - } - return JX9_OK; -} -/* - * string str_pad(string $input, int $pad_length[, string $pad_string = " " [, int $pad_type = STR_PAD_RIGHT]]) - * Pad a string to a certain length with another string - * Parameters - * $input - * The input string. - * $pad_length - * If the value of pad_length is negative, less than, or equal to the length of the input - * string, no padding takes place. - * $pad_string - * Note: - * The pad_string WIIL NOT BE truncated if the required number of padding characters can't be evenly - * divided by the pad_string's length. - * $pad_type - * Optional argument pad_type can be STR_PAD_RIGHT, STR_PAD_LEFT, or STR_PAD_BOTH. If pad_type - * is not specified it is assumed to be STR_PAD_RIGHT. - * Return - * The padded string. - */ -static int jx9Builtin_str_pad(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int iLen, iPadlen, iType, i, iDiv, iStrpad, iRealPad, jPad; - const char *zIn, *zPad; - if( nArg < 2 ){ - /* Missing arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = jx9_value_to_string(apArg[0], &iLen); - /* Padding length */ - iRealPad = iPadlen = jx9_value_to_int(apArg[1]); - if( iPadlen > 0 ){ - iPadlen -= iLen; - } - if( iPadlen < 1 ){ - /* Return the string verbatim */ - jx9_result_string(pCtx, zIn, iLen); - return JX9_OK; - } - zPad = " "; /* Whitespace padding */ - iStrpad = (int)sizeof(char); - iType = 1 ; /* STR_PAD_RIGHT */ - if( nArg > 2 ){ - /* Padding string */ - zPad = jx9_value_to_string(apArg[2], &iStrpad); - if( iStrpad < 1 ){ - /* Empty string */ - zPad = " "; /* Whitespace padding */ - iStrpad = (int)sizeof(char); - } - if( nArg > 3 ){ - /* Padd type */ - iType = jx9_value_to_int(apArg[3]); - if( iType != 0 /* STR_PAD_LEFT */ && iType != 2 /* STR_PAD_BOTH */ ){ - iType = 1 ; /* STR_PAD_RIGHT */ - } - } - } - iDiv = 1; - if( iType == 2 ){ - iDiv = 2; /* STR_PAD_BOTH */ - } - /* Perform the requested operation */ - if( iType == 0 /* STR_PAD_LEFT */ || iType == 2 /* STR_PAD_BOTH */ ){ - jPad = iStrpad; - for( i = 0 ; i < iPadlen/iDiv ; i += jPad ){ - /* Padding */ - if( (int)jx9_context_result_buf_length(pCtx) + iLen + jPad >= iRealPad ){ - break; - } - jx9_result_string(pCtx, zPad, jPad); - } - if( iType == 0 /* STR_PAD_LEFT */ ){ - while( (int)jx9_context_result_buf_length(pCtx) + iLen < iRealPad ){ - jPad = iRealPad - (iLen + (int)jx9_context_result_buf_length(pCtx) ); - if( jPad > iStrpad ){ - jPad = iStrpad; - } - if( jPad < 1){ - break; - } - jx9_result_string(pCtx, zPad, jPad); - } - } - } - if( iLen > 0 ){ - /* Append the input string */ - jx9_result_string(pCtx, zIn, iLen); - } - if( iType == 1 /* STR_PAD_RIGHT */ || iType == 2 /* STR_PAD_BOTH */ ){ - for( i = 0 ; i < iPadlen/iDiv ; i += iStrpad ){ - /* Padding */ - if( (int)jx9_context_result_buf_length(pCtx) + iStrpad >= iRealPad ){ - break; - } - jx9_result_string(pCtx, zPad, iStrpad); - } - while( (int)jx9_context_result_buf_length(pCtx) < iRealPad ){ - jPad = iRealPad - (int)jx9_context_result_buf_length(pCtx); - if( jPad > iStrpad ){ - jPad = iStrpad; - } - if( jPad < 1){ - break; - } - jx9_result_string(pCtx, zPad, jPad); - } - } - return JX9_OK; -} -/* - * String replacement private data. - */ -typedef struct str_replace_data str_replace_data; -struct str_replace_data -{ - /* The following two fields are only used by the strtr function */ - SyBlob *pWorker; /* Working buffer */ - ProcStringMatch xMatch; /* Pattern match routine */ - /* The following two fields are only used by the str_replace function */ - SySet *pCollector; /* Argument collector*/ - jx9_context *pCtx; /* Call context */ -}; -/* - * Remove a substring. - */ -#define STRDEL(SRC, SLEN, OFFT, ILEN){\ - for(;;){\ - if( OFFT + ILEN >= SLEN ) break; SRC[OFFT] = SRC[OFFT+ILEN]; ++OFFT;\ - }\ -} -/* - * Shift right and insert algorithm. - */ -#define SHIFTRANDINSERT(SRC, LEN, OFFT, ENTRY, ELEN){\ - sxu32 INLEN = LEN - OFFT;\ - for(;;){\ - if( LEN > 0 ){ LEN--; } if(INLEN < 1 ) break; SRC[LEN + ELEN] = SRC[LEN] ; --INLEN; \ - }\ - for(;;){\ - if(ELEN < 1)break; SRC[OFFT] = ENTRY[0]; OFFT++; ENTRY++; --ELEN;\ - }\ -} -/* - * Replace all occurrences of the search string at offset (nOfft) with the given - * replacement string [i.e: zReplace]. - */ -static int StringReplace(SyBlob *pWorker, sxu32 nOfft, int nLen, const char *zReplace, int nReplen) -{ - char *zInput = (char *)SyBlobData(pWorker); - sxu32 n, m; - n = SyBlobLength(pWorker); - m = nOfft; - /* Delete the old entry */ - STRDEL(zInput, n, m, nLen); - SyBlobLength(pWorker) -= nLen; - if( nReplen > 0 ){ - sxi32 iRep = nReplen; - sxi32 rc; - /* - * Make sure the working buffer is big enough to hold the replacement - * string. - */ - rc = SyBlobAppend(pWorker, 0/* Grow without an append operation*/, (sxu32)nReplen); - if( rc != SXRET_OK ){ - /* Simply ignore any memory failure problem */ - return SXRET_OK; - } - /* Perform the insertion now */ - zInput = (char *)SyBlobData(pWorker); - n = SyBlobLength(pWorker); - SHIFTRANDINSERT(zInput, n, nOfft, zReplace, iRep); - SyBlobLength(pWorker) += nReplen; - } - return SXRET_OK; -} -/* - * String replacement walker callback. - * The following callback is invoked for each array entry that hold - * the replace string. - * Refer to the strtr() implementation for more information. - */ -static int StringReplaceWalker(jx9_value *pKey, jx9_value *pData, void *pUserData) -{ - str_replace_data *pRepData = (str_replace_data *)pUserData; - const char *zTarget, *zReplace; - SyBlob *pWorker; - int tLen, nLen; - sxu32 nOfft; - sxi32 rc; - /* Point to the working buffer */ - pWorker = pRepData->pWorker; - if( !jx9_value_is_string(pKey) ){ - /* Target and replace must be a string */ - return JX9_OK; - } - /* Extract the target and the replace */ - zTarget = jx9_value_to_string(pKey, &tLen); - if( tLen < 1 ){ - /* Empty target, return immediately */ - return JX9_OK; - } - /* Perform a pattern search */ - rc = pRepData->xMatch(SyBlobData(pWorker), SyBlobLength(pWorker), (const void *)zTarget, (sxu32)tLen, &nOfft); - if( rc != SXRET_OK ){ - /* Pattern not found */ - return JX9_OK; - } - /* Extract the replace string */ - zReplace = jx9_value_to_string(pData, &nLen); - /* Perform the replace process */ - StringReplace(pWorker, nOfft, tLen, zReplace, nLen); - /* All done */ - return JX9_OK; -} -/* - * The following walker callback is invoked by the str_rplace() function inorder - * to collect search/replace string. - * This callback is invoked only if the given argument is of type array. - */ -static int StrReplaceWalker(jx9_value *pKey, jx9_value *pData, void *pUserData) -{ - str_replace_data *pRep = (str_replace_data *)pUserData; - SyString sWorker; - const char *zIn; - int nByte; - /* Extract a string representation of the given argument */ - zIn = jx9_value_to_string(pData, &nByte); - SyStringInitFromBuf(&sWorker, 0, 0); - if( nByte > 0 ){ - char *zDup; - /* Duplicate the chunk */ - zDup = (char *)jx9_context_alloc_chunk(pRep->pCtx, (unsigned int)nByte, FALSE, - TRUE /* Release the chunk automatically, upon this context is destroyd */ - ); - if( zDup == 0 ){ - /* Ignore any memory failure problem */ - jx9_context_throw_error(pRep->pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - return JX9_OK; - } - SyMemcpy(zIn, zDup, (sxu32)nByte); - /* Save the chunk */ - SyStringInitFromBuf(&sWorker, zDup, nByte); - } - /* Save for later processing */ - SySetPut(pRep->pCollector, (const void *)&sWorker); - /* All done */ - SXUNUSED(pKey); /* cc warning */ - return JX9_OK; -} -/* - * mixed str_replace(mixed $search, mixed $replace, mixed $subject[, int &$count ]) - * mixed str_ireplace(mixed $search, mixed $replace, mixed $subject[, int &$count ]) - * Replace all occurrences of the search string with the replacement string. - * Parameters - * If search and replace are arrays, then str_replace() takes a value from each - * array and uses them to search and replace on subject. If replace has fewer values - * than search, then an empty string is used for the rest of replacement values. - * If search is an array and replace is a string, then this replacement string is used - * for every value of search. The converse would not make sense, though. - * If search or replace are arrays, their elements are processed first to last. - * $search - * The value being searched for, otherwise known as the needle. An array may be used - * to designate multiple needles. - * $replace - * The replacement value that replaces found search values. An array may be used - * to designate multiple replacements. - * $subject - * The string or array being searched and replaced on, otherwise known as the haystack. - * If subject is an array, then the search and replace is performed with every entry - * of subject, and the return value is an array as well. - * $count (Not used) - * If passed, this will be set to the number of replacements performed. - * Return - * This function returns a string or an array with the replaced values. - */ -static int jx9Builtin_str_replace(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyString sTemp, *pSearch, *pReplace; - ProcStringMatch xMatch; - const char *zIn, *zFunc; - str_replace_data sRep; - SyBlob sWorker; - SySet sReplace; - SySet sSearch; - int rep_str; - int nByte; - sxi32 rc; - if( nArg < 3 ){ - /* Missing/Invalid arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Initialize fields */ - SySetInit(&sSearch, &pCtx->pVm->sAllocator, sizeof(SyString)); - SySetInit(&sReplace, &pCtx->pVm->sAllocator, sizeof(SyString)); - SyBlobInit(&sWorker, &pCtx->pVm->sAllocator); - SyZero(&sRep, sizeof(str_replace_data)); - sRep.pCtx = pCtx; - sRep.pCollector = &sSearch; - rep_str = 0; - /* Extract the subject */ - zIn = jx9_value_to_string(apArg[2], &nByte); - if( nByte < 1 ){ - /* Nothing to replace, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Copy the subject */ - SyBlobAppend(&sWorker, (const void *)zIn, (sxu32)nByte); - /* Search string */ - if( jx9_value_is_json_array(apArg[0]) ){ - /* Collect search string */ - jx9_array_walk(apArg[0], StrReplaceWalker, &sRep); - }else{ - /* Single pattern */ - zIn = jx9_value_to_string(apArg[0], &nByte); - if( nByte < 1 ){ - /* Return the subject untouched since no search string is available */ - jx9_result_value(pCtx, apArg[2]/* Subject as thrird argument*/); - return JX9_OK; - } - SyStringInitFromBuf(&sTemp, zIn, nByte); - /* Save for later processing */ - SySetPut(&sSearch, (const void *)&sTemp); - } - /* Replace string */ - if( jx9_value_is_json_array(apArg[1]) ){ - /* Collect replace string */ - sRep.pCollector = &sReplace; - jx9_array_walk(apArg[1], StrReplaceWalker, &sRep); - }else{ - /* Single needle */ - zIn = jx9_value_to_string(apArg[1], &nByte); - rep_str = 1; - SyStringInitFromBuf(&sTemp, zIn, nByte); - /* Save for later processing */ - SySetPut(&sReplace, (const void *)&sTemp); - } - /* Reset loop cursors */ - SySetResetCursor(&sSearch); - SySetResetCursor(&sReplace); - pReplace = pSearch = 0; /* cc warning */ - SyStringInitFromBuf(&sTemp, "", 0); - /* Extract function name */ - zFunc = jx9_function_name(pCtx); - /* Set the default pattern match routine */ - xMatch = SyBlobSearch; - if( SyStrncmp(zFunc, "str_ireplace", sizeof("str_ireplace") - 1) == 0 ){ - /* Case insensitive pattern match */ - xMatch = iPatternMatch; - } - /* Start the replace process */ - while( SXRET_OK == SySetGetNextEntry(&sSearch, (void **)&pSearch) ){ - sxu32 nCount, nOfft; - if( pSearch->nByte < 1 ){ - /* Empty string, ignore */ - continue; - } - /* Extract the replace string */ - if( rep_str ){ - pReplace = (SyString *)SySetPeek(&sReplace); - }else{ - if( SXRET_OK != SySetGetNextEntry(&sReplace, (void **)&pReplace) ){ - /* Sepecial case when 'replace set' has fewer values than the search set. - * An empty string is used for the rest of replacement values - */ - pReplace = 0; - } - } - if( pReplace == 0 ){ - /* Use an empty string instead */ - pReplace = &sTemp; - } - nOfft = nCount = 0; - for(;;){ - if( nCount >= SyBlobLength(&sWorker) ){ - break; - } - /* Perform a pattern lookup */ - rc = xMatch(SyBlobDataAt(&sWorker, nCount), SyBlobLength(&sWorker) - nCount, (const void *)pSearch->zString, - pSearch->nByte, &nOfft); - if( rc != SXRET_OK ){ - /* Pattern not found */ - break; - } - /* Perform the replace operation */ - StringReplace(&sWorker, nCount+nOfft, (int)pSearch->nByte, pReplace->zString, (int)pReplace->nByte); - /* Increment offset counter */ - nCount += nOfft + pReplace->nByte; - } - } - /* All done, clean-up the mess left behind */ - jx9_result_string(pCtx, (const char *)SyBlobData(&sWorker), (int)SyBlobLength(&sWorker)); - SySetRelease(&sSearch); - SySetRelease(&sReplace); - SyBlobRelease(&sWorker); - return JX9_OK; -} -/* - * string strtr(string $str, string $from, string $to) - * string strtr(string $str, array $replace_pairs) - * Translate characters or replace substrings. - * Parameters - * $str - * The string being translated. - * $from - * The string being translated to to. - * $to - * The string replacing from. - * $replace_pairs - * The replace_pairs parameter may be used instead of to and - * from, in which case it's an array in the form array('from' => 'to', ...). - * Return - * The translated string. - * If replace_pairs contains a key which is an empty string (""), FALSE will be returned. - */ -static int jx9Builtin_strtr(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn; - int nLen; - if( nArg < 1 ){ - /* Nothing to replace, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 || nArg < 2 ){ - /* Invalid arguments */ - jx9_result_string(pCtx, zIn, nLen); - return JX9_OK; - } - if( nArg == 2 && jx9_value_is_json_array(apArg[1]) ){ - str_replace_data sRepData; - SyBlob sWorker; - /* Initilaize the working buffer */ - SyBlobInit(&sWorker, &pCtx->pVm->sAllocator); - /* Copy raw string */ - SyBlobAppend(&sWorker, (const void *)zIn, (sxu32)nLen); - /* Init our replace data instance */ - sRepData.pWorker = &sWorker; - sRepData.xMatch = SyBlobSearch; - /* Iterate throw array entries and perform the replace operation.*/ - jx9_array_walk(apArg[1], StringReplaceWalker, &sRepData); - /* All done, return the result string */ - jx9_result_string(pCtx, (const char *)SyBlobData(&sWorker), - (int)SyBlobLength(&sWorker)); /* Will make it's own copy */ - /* Clean-up */ - SyBlobRelease(&sWorker); - }else{ - int i, flen, tlen, c, iOfft; - const char *zFrom, *zTo; - if( nArg < 3 ){ - /* Nothing to replace */ - jx9_result_string(pCtx, zIn, nLen); - return JX9_OK; - } - /* Extract given arguments */ - zFrom = jx9_value_to_string(apArg[1], &flen); - zTo = jx9_value_to_string(apArg[2], &tlen); - if( flen < 1 || tlen < 1 ){ - /* Nothing to replace */ - jx9_result_string(pCtx, zIn, nLen); - return JX9_OK; - } - /* Start the replace process */ - for( i = 0 ; i < nLen ; ++i ){ - c = zIn[i]; - if( CheckMask(c, zFrom, flen, &iOfft) ){ - if ( iOfft < tlen ){ - c = zTo[iOfft]; - } - } - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - - } - } - return JX9_OK; -} -/* - * Parse an INI string. - * According to wikipedia - * The INI file format is an informal standard for configuration files for some platforms or software. - * INI files are simple text files with a basic structure composed of "sections" and "properties". - * Format -* Properties -* The basic element contained in an INI file is the property. Every property has a name and a value -* delimited by an equals sign (=). The name appears to the left of the equals sign. -* Example: -* name=value -* Sections -* Properties may be grouped into arbitrarily named sections. The section name appears on a line by itself -* in square brackets ([ and ]). All properties after the section declaration are associated with that section. -* There is no explicit "end of section" delimiter; sections end at the next section declaration -* or the end of the file. Sections may not be nested. -* Example: -* [section] -* Comments -* Semicolons (;) at the beginning of the line indicate a comment. Comment lines are ignored. -* This function return an array holding parsed values on success.FALSE otherwise. -*/ -JX9_PRIVATE sxi32 jx9ParseIniString(jx9_context *pCtx, const char *zIn, sxu32 nByte, int bProcessSection) -{ - jx9_value *pCur, *pArray, *pSection, *pWorker, *pValue; - const char *zCur, *zEnd = &zIn[nByte]; - SyHashEntry *pEntry; - SyString sEntry; - SyHash sHash; - int c; - /* Create an empty array and worker variables */ - pArray = jx9_context_new_array(pCtx); - pWorker = jx9_context_new_scalar(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pWorker == 0 || pValue == 0){ - /* Out of memory */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - /* Return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - SyHashInit(&sHash, &pCtx->pVm->sAllocator, 0, 0); - pCur = pArray; - /* Start the parse process */ - for(;;){ - /* Ignore leading white spaces */ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0])){ - zIn++; - } - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - if( zIn[0] == ';' || zIn[0] == '#' ){ - /* Comment til the end of line */ - zIn++; - while(zIn < zEnd && zIn[0] != '\n' ){ - zIn++; - } - continue; - } - /* Reset the string cursor of the working variable */ - jx9_value_reset_string_cursor(pWorker); - if( zIn[0] == '[' ){ - /* Section: Extract the section name */ - zIn++; - zCur = zIn; - while( zIn < zEnd && zIn[0] != ']' ){ - zIn++; - } - if( zIn > zCur && bProcessSection ){ - /* Save the section name */ - SyStringInitFromBuf(&sEntry, zCur, (int)(zIn-zCur)); - SyStringFullTrim(&sEntry); - jx9_value_string(pWorker, sEntry.zString, (int)sEntry.nByte); - if( sEntry.nByte > 0 ){ - /* Associate an array with the section */ - pSection = jx9_context_new_array(pCtx); - if( pSection ){ - jx9_array_add_elem(pArray, pWorker/*Section name*/, pSection); - pCur = pSection; - } - } - } - zIn++; /* Trailing square brackets ']' */ - }else{ - jx9_value *pOldCur; - int is_array; - int iLen; - /* Properties */ - is_array = 0; - zCur = zIn; - iLen = 0; /* cc warning */ - pOldCur = pCur; - while( zIn < zEnd && zIn[0] != '=' ){ - if( zIn[0] == '[' && !is_array ){ - /* Array */ - iLen = (int)(zIn-zCur); - is_array = 1; - if( iLen > 0 ){ - jx9_value *pvArr = 0; /* cc warning */ - /* Query the hashtable */ - SyStringInitFromBuf(&sEntry, zCur, iLen); - SyStringFullTrim(&sEntry); - pEntry = SyHashGet(&sHash, (const void *)sEntry.zString, sEntry.nByte); - if( pEntry ){ - pvArr = (jx9_value *)SyHashEntryGetUserData(pEntry); - }else{ - /* Create an empty array */ - pvArr = jx9_context_new_array(pCtx); - if( pvArr ){ - /* Save the entry */ - SyHashInsert(&sHash, (const void *)sEntry.zString, sEntry.nByte, pvArr); - /* Insert the entry */ - jx9_value_reset_string_cursor(pWorker); - jx9_value_string(pWorker, sEntry.zString, (int)sEntry.nByte); - jx9_array_add_elem(pCur, pWorker, pvArr); - jx9_value_reset_string_cursor(pWorker); - } - } - if( pvArr ){ - pCur = pvArr; - } - } - while ( zIn < zEnd && zIn[0] != ']' ){ - zIn++; - } - } - zIn++; - } - if( !is_array ){ - iLen = (int)(zIn-zCur); - } - /* Trim the key */ - SyStringInitFromBuf(&sEntry, zCur, iLen); - SyStringFullTrim(&sEntry); - if( sEntry.nByte > 0 ){ - if( !is_array ){ - /* Save the key name */ - jx9_value_string(pWorker, sEntry.zString, (int)sEntry.nByte); - } - /* extract key value */ - jx9_value_reset_string_cursor(pValue); - zIn++; /* '=' */ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ - zIn++; - } - if( zIn < zEnd ){ - zCur = zIn; - c = zIn[0]; - if( c == '"' || c == '\'' ){ - zIn++; - /* Delimit the value */ - while( zIn < zEnd ){ - if ( zIn[0] == c && zIn[-1] != '\\' ){ - break; - } - zIn++; - } - if( zIn < zEnd ){ - zIn++; - } - }else{ - while( zIn < zEnd ){ - if( zIn[0] == '\n' ){ - if( zIn[-1] != '\\' ){ - break; - } - }else if( zIn[0] == ';' || zIn[0] == '#' ){ - /* Inline comments */ - break; - } - zIn++; - } - } - /* Trim the value */ - SyStringInitFromBuf(&sEntry, zCur, (int)(zIn-zCur)); - SyStringFullTrim(&sEntry); - if( c == '"' || c == '\'' ){ - SyStringTrimLeadingChar(&sEntry, c); - SyStringTrimTrailingChar(&sEntry, c); - } - if( sEntry.nByte > 0 ){ - jx9_value_string(pValue, sEntry.zString, (int)sEntry.nByte); - } - /* Insert the key and it's value */ - jx9_array_add_elem(pCur, is_array ? 0 /*Automatic index assign */: pWorker, pValue); - } - }else{ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && ( SyisSpace(zIn[0]) || zIn[0] == '=' ) ){ - zIn++; - } - } - pCur = pOldCur; - } - } - SyHashRelease(&sHash); - /* Return the parse of the INI string */ - jx9_result_value(pCtx, pArray); - return SXRET_OK; -} -/* - * array parse_ini_string(string $ini[, bool $process_sections = false[, int $scanner_mode = INI_SCANNER_NORMAL ]]) - * Parse a configuration string. - * Parameters - * $ini - * The contents of the ini file being parsed. - * $process_sections - * By setting the process_sections parameter to TRUE, you get a multidimensional array, with the section names - * and settings included. The default for process_sections is FALSE. - * $scanner_mode (Not used) - * Can either be INI_SCANNER_NORMAL (default) or INI_SCANNER_RAW. If INI_SCANNER_RAW is supplied - * then option values will not be parsed. - * Return - * The settings are returned as an associative array on success, and FALSE on failure. - */ -static int jx9Builtin_parse_ini_string(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIni; - int nByte; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE*/ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the raw INI buffer */ - zIni = jx9_value_to_string(apArg[0], &nByte); - /* Process the INI buffer*/ - jx9ParseIniString(pCtx, zIni, (sxu32)nByte, (nArg > 1) ? jx9_value_to_bool(apArg[1]) : 0); - return JX9_OK; -} -/* - * Ctype Functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * bool ctype_alnum(string $text) - * Checks if all of the characters in the provided string, text, are alphanumeric. - * Parameters - * $text - * The tested string. - * Return - * TRUE if every character in text is either a letter or a digit, FALSE otherwise. - */ -static int jx9Builtin_ctype_alnum(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( !SyisAlphaNum(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_alpha(string $text) - * Checks if all of the characters in the provided string, text, are alphabetic. - * Parameters - * $text - * The tested string. - * Return - * TRUE if every character in text is a letter from the current locale, FALSE otherwise. - */ -static int jx9Builtin_ctype_alpha(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( !SyisAlpha(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_cntrl(string $text) - * Checks if all of the characters in the provided string, text, are control characters. - * Parameters - * $text - * The tested string. - * Return - * TRUE if every character in text is a control characters, FALSE otherwise. - */ -static int jx9Builtin_ctype_cntrl(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - break; - } - if( !SyisCtrl(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_digit(string $text) - * Checks if all of the characters in the provided string, text, are numerical. - * Parameters - * $text - * The tested string. - * Return - * TRUE if every character in the string text is a decimal digit, FALSE otherwise. - */ -static int jx9Builtin_ctype_digit(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - break; - } - if( !SyisDigit(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_xdigit(string $text) - * Check for character(s) representing a hexadecimal digit. - * Parameters - * $text - * The tested string. - * Return - * Returns TRUE if every character in text is a hexadecimal 'digit', that is - * a decimal digit or a character from [A-Fa-f] , FALSE otherwise. - */ -static int jx9Builtin_ctype_xdigit(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - break; - } - if( !SyisHex(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_graph(string $text) - * Checks if all of the characters in the provided string, text, creates visible output. - * Parameters - * $text - * The tested string. - * Return - * Returns TRUE if every character in text is printable and actually creates visible output - * (no white space), FALSE otherwise. - */ -static int jx9Builtin_ctype_graph(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - break; - } - if( !SyisGraph(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_print(string $text) - * Checks if all of the characters in the provided string, text, are printable. - * Parameters - * $text - * The tested string. - * Return - * Returns TRUE if every character in text will actually create output (including blanks). - * Returns FALSE if text contains control characters or characters that do not have any output - * or control function at all. - */ -static int jx9Builtin_ctype_print(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - break; - } - if( !SyisPrint(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_punct(string $text) - * Checks if all of the characters in the provided string, text, are punctuation character. - * Parameters - * $text - * The tested string. - * Return - * Returns TRUE if every character in text is printable, but neither letter - * digit or blank, FALSE otherwise. - */ -static int jx9Builtin_ctype_punct(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - break; - } - if( !SyisPunct(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_space(string $text) - * Checks if all of the characters in the provided string, text, creates whitespace. - * Parameters - * $text - * The tested string. - * Return - * Returns TRUE if every character in text creates some sort of white space, FALSE otherwise. - * Besides the blank character this also includes tab, vertical tab, line feed, carriage return - * and form feed characters. - */ -static int jx9Builtin_ctype_space(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - break; - } - if( !SyisSpace(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_lower(string $text) - * Checks if all of the characters in the provided string, text, are lowercase letters. - * Parameters - * $text - * The tested string. - * Return - * Returns TRUE if every character in text is a lowercase letter in the current locale. - */ -static int jx9Builtin_ctype_lower(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( !SyisLower(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * bool ctype_upper(string $text) - * Checks if all of the characters in the provided string, text, are uppercase letters. - * Parameters - * $text - * The tested string. - * Return - * Returns TRUE if every character in text is a uppercase letter in the current locale. - */ -static int jx9Builtin_ctype_upper(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nLen); - zEnd = &zIn[nLen]; - if( nLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - if( zIn >= zEnd ){ - /* If we reach the end of the string, then the test succeeded. */ - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - if( !SyisUpper(zIn[0]) ){ - break; - } - /* Point to the next character */ - zIn++; - } - /* The test failed, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; -} -/* - * Date/Time functions - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Devel. - */ -#include -#ifdef __WINNT__ -/* GetSystemTime() */ -#include -#ifdef _WIN32_WCE -/* -** WindowsCE does not have a localtime() function. So create a -** substitute. -** Taken from the SQLite3 source tree. -** Status: Public domain -*/ -struct tm *__cdecl localtime(const time_t *t) -{ - static struct tm y; - FILETIME uTm, lTm; - SYSTEMTIME pTm; - jx9_int64 t64; - t64 = *t; - t64 = (t64 + 11644473600)*10000000; - uTm.dwLowDateTime = (DWORD)(t64 & 0xFFFFFFFF); - uTm.dwHighDateTime= (DWORD)(t64 >> 32); - FileTimeToLocalFileTime(&uTm, &lTm); - FileTimeToSystemTime(&lTm, &pTm); - y.tm_year = pTm.wYear - 1900; - y.tm_mon = pTm.wMonth - 1; - y.tm_wday = pTm.wDayOfWeek; - y.tm_mday = pTm.wDay; - y.tm_hour = pTm.wHour; - y.tm_min = pTm.wMinute; - y.tm_sec = pTm.wSecond; - return &y; -} -#endif /*_WIN32_WCE */ -#elif defined(__UNIXES__) -#include -#endif /* __WINNT__*/ - /* - * int64 time(void) - * Current Unix timestamp - * Parameters - * None. - * Return - * Returns the current time measured in the number of seconds - * since the Unix Epoch (January 1 1970 00:00:00 GMT). - */ -static int jx9Builtin_time(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - time_t tt; - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* Extract the current time */ - time(&tt); - /* Return as 64-bit integer */ - jx9_result_int64(pCtx, (jx9_int64)tt); - return JX9_OK; -} -/* - * string/float microtime([ bool $get_as_float = false ]) - * microtime() returns the current Unix timestamp with microseconds. - * Parameters - * $get_as_float - * If used and set to TRUE, microtime() will return a float instead of a string - * as described in the return values section below. - * Return - * By default, microtime() returns a string in the form "msec sec", where sec - * is the current time measured in the number of seconds since the Unix - * epoch (0:00:00 January 1, 1970 GMT), and msec is the number of microseconds - * that have elapsed since sec expressed in seconds. - * If get_as_float is set to TRUE, then microtime() returns a float, which represents - * the current time in seconds since the Unix epoch accurate to the nearest microsecond. - */ -static int jx9Builtin_microtime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int bFloat = 0; - sytime sTime; -#if defined(__UNIXES__) - struct timeval tv; - gettimeofday(&tv, 0); - sTime.tm_sec = (long)tv.tv_sec; - sTime.tm_usec = (long)tv.tv_usec; -#else - time_t tt; - time(&tt); - sTime.tm_sec = (long)tt; - sTime.tm_usec = (long)(tt%SX_USEC_PER_SEC); -#endif /* __UNIXES__ */ - if( nArg > 0 ){ - bFloat = jx9_value_to_bool(apArg[0]); - } - if( bFloat ){ - /* Return as float */ - jx9_result_double(pCtx, (double)sTime.tm_sec); - }else{ - /* Return as string */ - jx9_result_string_format(pCtx, "%ld %ld", sTime.tm_usec, sTime.tm_sec); - } - return JX9_OK; -} -/* - * array getdate ([ int $timestamp = time() ]) - * Get date/time information. - * Parameter - * $timestamp: The optional timestamp parameter is an integer Unix timestamp - * that defaults to the current local time if a timestamp is not given. - * In other words, it defaults to the value of time(). - * Returns - * Returns an associative array of information related to the timestamp. - * Elements from the returned associative array are as follows: - * KEY VALUE - * --------- ------- - * "seconds" Numeric representation of seconds 0 to 59 - * "minutes" Numeric representation of minutes 0 to 59 - * "hours" Numeric representation of hours 0 to 23 - * "mday" Numeric representation of the day of the month 1 to 31 - * "wday" Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday) - * "mon" Numeric representation of a month 1 through 12 - * "year" A full numeric representation of a year, 4 digits Examples: 1999 or 2003 - * "yday" Numeric representation of the day of the year 0 through 365 - * "weekday" A full textual representation of the day of the week Sunday through Saturday - * "month" A full textual representation of a month, such as January or March January through December - * 0 Seconds since the Unix Epoch, similar to the values returned by time() and used by date(). - * NOTE: - * NULL is returned on failure. - */ -static int jx9Builtin_getdate(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pValue, *pArray; - Sytm sTm; - if( nArg < 1 ){ -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - }else{ - /* Use the given timestamp */ - time_t t; - struct tm *pTm; -#ifdef __WINNT__ -#ifdef _MSC_VER -#if _MSC_VER >= 1400 /* Visual Studio 2005 and up */ -#pragma warning(disable:4996) /* _CRT_SECURE...*/ -#endif -#endif -#endif - if( jx9_value_is_int(apArg[0]) ){ - t = (time_t)jx9_value_to_int64(apArg[0]); - pTm = localtime(&t); - if( pTm == 0 ){ - time(&t); - } - }else{ - time(&t); - } - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); - } - /* Element value */ - pValue = jx9_context_new_scalar(pCtx); - if( pValue == 0 ){ - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Fill the array */ - /* Seconds */ - jx9_value_int(pValue, sTm.tm_sec); - jx9_array_add_strkey_elem(pArray, "seconds", pValue); - /* Minutes */ - jx9_value_int(pValue, sTm.tm_min); - jx9_array_add_strkey_elem(pArray, "minutes", pValue); - /* Hours */ - jx9_value_int(pValue, sTm.tm_hour); - jx9_array_add_strkey_elem(pArray, "hours", pValue); - /* mday */ - jx9_value_int(pValue, sTm.tm_mday); - jx9_array_add_strkey_elem(pArray, "mday", pValue); - /* wday */ - jx9_value_int(pValue, sTm.tm_wday); - jx9_array_add_strkey_elem(pArray, "wday", pValue); - /* mon */ - jx9_value_int(pValue, sTm.tm_mon+1); - jx9_array_add_strkey_elem(pArray, "mon", pValue); - /* year */ - jx9_value_int(pValue, sTm.tm_year); - jx9_array_add_strkey_elem(pArray, "year", pValue); - /* yday */ - jx9_value_int(pValue, sTm.tm_yday); - jx9_array_add_strkey_elem(pArray, "yday", pValue); - /* Weekday */ - jx9_value_string(pValue, SyTimeGetDay(sTm.tm_wday), -1); - jx9_array_add_strkey_elem(pArray, "weekday", pValue); - /* Month */ - jx9_value_reset_string_cursor(pValue); - jx9_value_string(pValue, SyTimeGetMonth(sTm.tm_mon), -1); - jx9_array_add_strkey_elem(pArray, "month", pValue); - /* Seconds since the epoch */ - jx9_value_int64(pValue, (jx9_int64)time(0)); - jx9_array_add_elem(pArray, 0 /* Index zero */, pValue); - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * mixed gettimeofday([ bool $return_float = false ] ) - * Returns an associative array containing the data returned from the system call. - * Parameters - * $return_float - * When set to TRUE, a float instead of an array is returned. - * Return - * By default an array is returned. If return_float is set, then - * a float is returned. - */ -static int jx9Builtin_gettimeofday(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int bFloat = 0; - sytime sTime; -#if defined(__UNIXES__) - struct timeval tv; - gettimeofday(&tv, 0); - sTime.tm_sec = (long)tv.tv_sec; - sTime.tm_usec = (long)tv.tv_usec; -#else - time_t tt; - time(&tt); - sTime.tm_sec = (long)tt; - sTime.tm_usec = (long)(tt%SX_USEC_PER_SEC); -#endif /* __UNIXES__ */ - if( nArg > 0 ){ - bFloat = jx9_value_to_bool(apArg[0]); - } - if( bFloat ){ - /* Return as float */ - jx9_result_double(pCtx, (double)sTime.tm_sec); - }else{ - /* Return an associative array */ - jx9_value *pValue, *pArray; - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - /* Element value */ - pValue = jx9_context_new_scalar(pCtx); - if( pValue == 0 || pArray == 0 ){ - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Fill the array */ - /* sec */ - jx9_value_int64(pValue, sTime.tm_sec); - jx9_array_add_strkey_elem(pArray, "sec", pValue); - /* usec */ - jx9_value_int64(pValue, sTime.tm_usec); - jx9_array_add_strkey_elem(pArray, "usec", pValue); - /* Return the array */ - jx9_result_value(pCtx, pArray); - } - return JX9_OK; -} -/* Check if the given year is leap or not */ -#define IS_LEAP_YEAR(YEAR) (YEAR % 400 ? ( YEAR % 100 ? ( YEAR % 4 ? 0 : 1 ) : 0 ) : 1) -/* ISO-8601 numeric representation of the day of the week */ -static const int aISO8601[] = { 7 /* Sunday */, 1 /* Monday */, 2, 3, 4, 5, 6 }; -/* - * Format a given date string. - * Supported format: (Taken from JX9 online docs) - * character Description - * d Day of the month - * D A textual representation of a days - * j Day of the month without leading zeros - * l A full textual representation of the day of the week - * N ISO-8601 numeric representation of the day of the week - * w Numeric representation of the day of the week - * z The day of the year (starting from 0) - * F A full textual representation of a month, such as January or March - * m Numeric representation of a month, with leading zeros 01 through 12 - * M A short textual representation of a month, three letters Jan through Dec - * n Numeric representation of a month, without leading zeros 1 through 12 - * t Number of days in the given month 28 through 31 - * L Whether it's a leap year 1 if it is a leap year, 0 otherwise. - * o ISO-8601 year number. This has the same value as Y, except that if the ISO week number - * (W) belongs to the previous or next year, that year is used instead. (added in JX9 5.1.0) Examples: 1999 or 2003 - * Y A full numeric representation of a year, 4 digits Examples: 1999 or 2003 - * y A two digit representation of a year Examples: 99 or 03 - * a Lowercase Ante meridiem and Post meridiem am or pm - * A Uppercase Ante meridiem and Post meridiem AM or PM - * g 12-hour format of an hour without leading zeros 1 through 12 - * G 24-hour format of an hour without leading zeros 0 through 23 - * h 12-hour format of an hour with leading zeros 01 through 12 - * H 24-hour format of an hour with leading zeros 00 through 23 - * i Minutes with leading zeros 00 to 59 - * s Seconds, with leading zeros 00 through 59 - * u Microseconds Example: 654321 - * e Timezone identifier Examples: UTC, GMT, Atlantic/Azores - * I (capital i) Whether or not the date is in daylight saving time 1 if Daylight Saving Time, 0 otherwise. - * r RFC 2822 formatted date Example: Thu, 21 Dec 2000 16:01:07 +0200 - * U Seconds since the Unix Epoch (January 1 1970 00:00:00 GMT) - * S English ordinal suffix for the day of the month, 2 characters - * O Difference to Greenwich time (GMT) in hours - * Z Timezone offset in seconds. The offset for timezones west of UTC is always negative, and for those - * east of UTC is always positive. - * c ISO 8601 date - */ -static sxi32 DateFormat(jx9_context *pCtx, const char *zIn, int nLen, Sytm *pTm) -{ - const char *zEnd = &zIn[nLen]; - const char *zCur; - /* Start the format process */ - for(;;){ - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - switch(zIn[0]){ - case 'd': - /* Day of the month, 2 digits with leading zeros */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_mday); - break; - case 'D': - /*A textual representation of a day, three letters*/ - zCur = SyTimeGetDay(pTm->tm_wday); - jx9_result_string(pCtx, zCur, 3); - break; - case 'j': - /* Day of the month without leading zeros */ - jx9_result_string_format(pCtx, "%d", pTm->tm_mday); - break; - case 'l': - /* A full textual representation of the day of the week */ - zCur = SyTimeGetDay(pTm->tm_wday); - jx9_result_string(pCtx, zCur, -1/*Compute length automatically*/); - break; - case 'N':{ - /* ISO-8601 numeric representation of the day of the week */ - jx9_result_string_format(pCtx, "%d", aISO8601[pTm->tm_wday % 7 ]); - break; - } - case 'w': - /*Numeric representation of the day of the week*/ - jx9_result_string_format(pCtx, "%d", pTm->tm_wday); - break; - case 'z': - /*The day of the year*/ - jx9_result_string_format(pCtx, "%d", pTm->tm_yday); - break; - case 'F': - /*A full textual representation of a month, such as January or March*/ - zCur = SyTimeGetMonth(pTm->tm_mon); - jx9_result_string(pCtx, zCur, -1/*Compute length automatically*/); - break; - case 'm': - /*Numeric representation of a month, with leading zeros*/ - jx9_result_string_format(pCtx, "%02d", pTm->tm_mon + 1); - break; - case 'M': - /*A short textual representation of a month, three letters*/ - zCur = SyTimeGetMonth(pTm->tm_mon); - jx9_result_string(pCtx, zCur, 3); - break; - case 'n': - /*Numeric representation of a month, without leading zeros*/ - jx9_result_string_format(pCtx, "%d", pTm->tm_mon + 1); - break; - case 't':{ - static const int aMonDays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - int nDays = aMonDays[pTm->tm_mon % 12 ]; - if( pTm->tm_mon == 1 /* 'February' */ && !IS_LEAP_YEAR(pTm->tm_year) ){ - nDays = 28; - } - /*Number of days in the given month*/ - jx9_result_string_format(pCtx, "%d", nDays); - break; - } - case 'L':{ - int isLeap = IS_LEAP_YEAR(pTm->tm_year); - /* Whether it's a leap year */ - jx9_result_string_format(pCtx, "%d", isLeap); - break; - } - case 'o': - /* ISO-8601 year number.*/ - jx9_result_string_format(pCtx, "%4d", pTm->tm_year); - break; - case 'Y': - /* A full numeric representation of a year, 4 digits */ - jx9_result_string_format(pCtx, "%4d", pTm->tm_year); - break; - case 'y': - /*A two digit representation of a year*/ - jx9_result_string_format(pCtx, "%02d", pTm->tm_year%100); - break; - case 'a': - /* Lowercase Ante meridiem and Post meridiem */ - jx9_result_string(pCtx, pTm->tm_hour > 12 ? "pm" : "am", 2); - break; - case 'A': - /* Uppercase Ante meridiem and Post meridiem */ - jx9_result_string(pCtx, pTm->tm_hour > 12 ? "PM" : "AM", 2); - break; - case 'g': - /* 12-hour format of an hour without leading zeros*/ - jx9_result_string_format(pCtx, "%d", 1+(pTm->tm_hour%12)); - break; - case 'G': - /* 24-hour format of an hour without leading zeros */ - jx9_result_string_format(pCtx, "%d", pTm->tm_hour); - break; - case 'h': - /* 12-hour format of an hour with leading zeros */ - jx9_result_string_format(pCtx, "%02d", 1+(pTm->tm_hour%12)); - break; - case 'H': - /* 24-hour format of an hour with leading zeros */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_hour); - break; - case 'i': - /* Minutes with leading zeros */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_min); - break; - case 's': - /* second with leading zeros */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_sec); - break; - case 'u': - /* Microseconds */ - jx9_result_string_format(pCtx, "%u", pTm->tm_sec * SX_USEC_PER_SEC); - break; - case 'S':{ - /* English ordinal suffix for the day of the month, 2 characters */ - static const char zSuffix[] = "thstndrdthththththth"; - int v = pTm->tm_mday; - jx9_result_string(pCtx, &zSuffix[2 * (int)(v / 10 % 10 != 1 ? v % 10 : 0)], (int)sizeof(char) * 2); - break; - } - case 'e': - /* Timezone identifier */ - zCur = pTm->tm_zone; - if( zCur == 0 ){ - /* Assume GMT */ - zCur = "GMT"; - } - jx9_result_string(pCtx, zCur, -1); - break; - case 'I': - /* Whether or not the date is in daylight saving time */ -#ifdef __WINNT__ -#ifdef _MSC_VER -#ifndef _WIN32_WCE - _get_daylight(&pTm->tm_isdst); -#endif -#endif -#endif - jx9_result_string_format(pCtx, "%d", pTm->tm_isdst == 1); - break; - case 'r': - /* RFC 2822 formatted date Example: Thu, 21 Dec 2000 16:01:07 */ - jx9_result_string_format(pCtx, "%.3s, %02d %.3s %4d %02d:%02d:%02d", - SyTimeGetDay(pTm->tm_wday), - pTm->tm_mday, - SyTimeGetMonth(pTm->tm_mon), - pTm->tm_year, - pTm->tm_hour, - pTm->tm_min, - pTm->tm_sec - ); - break; - case 'U':{ - time_t tt; - /* Seconds since the Unix Epoch */ - time(&tt); - jx9_result_string_format(pCtx, "%u", (unsigned int)tt); - break; - } - case 'O': - case 'P': - /* Difference to Greenwich time (GMT) in hours */ - jx9_result_string_format(pCtx, "%+05d", pTm->tm_gmtoff); - break; - case 'Z': - /* Timezone offset in seconds. The offset for timezones west of UTC - * is always negative, and for those east of UTC is always positive. - */ - jx9_result_string_format(pCtx, "%+05d", pTm->tm_gmtoff); - break; - case 'c': - /* ISO 8601 date */ - jx9_result_string_format(pCtx, "%4d-%02d-%02dT%02d:%02d:%02d%+05d", - pTm->tm_year, - pTm->tm_mon+1, - pTm->tm_mday, - pTm->tm_hour, - pTm->tm_min, - pTm->tm_sec, - pTm->tm_gmtoff - ); - break; - case '\\': - zIn++; - /* Expand verbatim */ - if( zIn < zEnd ){ - jx9_result_string(pCtx, zIn, (int)sizeof(char)); - } - break; - default: - /* Unknown format specifer, expand verbatim */ - jx9_result_string(pCtx, zIn, (int)sizeof(char)); - break; - } - /* Point to the next character */ - zIn++; - } - return SXRET_OK; -} -/* - * JX9 implementation of the strftime() function. - * The following formats are supported: - * %a An abbreviated textual representation of the day - * %A A full textual representation of the day - * %d Two-digit day of the month (with leading zeros) - * %e Day of the month, with a space preceding single digits. - * %j Day of the year, 3 digits with leading zeros - * %u ISO-8601 numeric representation of the day of the week 1 (for Monday) though 7 (for Sunday) - * %w Numeric representation of the day of the week 0 (for Sunday) through 6 (for Saturday) - * %U Week number of the given year, starting with the first Sunday as the first week - * %V ISO-8601:1988 week number of the given year, starting with the first week of the year with at least - * 4 weekdays, with Monday being the start of the week. - * %W A numeric representation of the week of the year - * %b Abbreviated month name, based on the locale - * %B Full month name, based on the locale - * %h Abbreviated month name, based on the locale (an alias of %b) - * %m Two digit representation of the month - * %C Two digit representation of the century (year divided by 100, truncated to an integer) - * %g Two digit representation of the year going by ISO-8601:1988 standards (see %V) - * %G The full four-digit version of %g - * %y Two digit representation of the year - * %Y Four digit representation for the year - * %H Two digit representation of the hour in 24-hour format - * %I Two digit representation of the hour in 12-hour format - * %l (lower-case 'L') Hour in 12-hour format, with a space preceeding single digits - * %M Two digit representation of the minute - * %p UPPER-CASE 'AM' or 'PM' based on the given time - * %P lower-case 'am' or 'pm' based on the given time - * %r Same as "%I:%M:%S %p" - * %R Same as "%H:%M" - * %S Two digit representation of the second - * %T Same as "%H:%M:%S" - * %X Preferred time representation based on locale, without the date - * %z Either the time zone offset from UTC or the abbreviation - * %Z The time zone offset/abbreviation option NOT given by %z - * %c Preferred date and time stamp based on local - * %D Same as "%m/%d/%y" - * %F Same as "%Y-%m-%d" - * %s Unix Epoch Time timestamp (same as the time() function) - * %x Preferred date representation based on locale, without the time - * %n A newline character ("\n") - * %t A Tab character ("\t") - * %% A literal percentage character ("%") - */ -static int jx9Strftime( - jx9_context *pCtx, /* Call context */ - const char *zIn, /* Input string */ - int nLen, /* Input length */ - Sytm *pTm /* Parse of the given time */ - ) -{ - const char *zCur, *zEnd = &zIn[nLen]; - int c; - /* Start the format process */ - for(;;){ - zCur = zIn; - while(zIn < zEnd && zIn[0] != '%' ){ - zIn++; - } - if( zIn > zCur ){ - /* Consume input verbatim */ - jx9_result_string(pCtx, zCur, (int)(zIn-zCur)); - } - zIn++; /* Jump the percent sign */ - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - c = zIn[0]; - /* Act according to the current specifer */ - switch(c){ - case '%': - /* A literal percentage character ("%") */ - jx9_result_string(pCtx, "%", (int)sizeof(char)); - break; - case 't': - /* A Tab character */ - jx9_result_string(pCtx, "\t", (int)sizeof(char)); - break; - case 'n': - /* A newline character */ - jx9_result_string(pCtx, "\n", (int)sizeof(char)); - break; - case 'a': - /* An abbreviated textual representation of the day */ - jx9_result_string(pCtx, SyTimeGetDay(pTm->tm_wday), (int)sizeof(char)*3); - break; - case 'A': - /* A full textual representation of the day */ - jx9_result_string(pCtx, SyTimeGetDay(pTm->tm_wday), -1/*Compute length automatically*/); - break; - case 'e': - /* Day of the month, 2 digits with leading space for single digit*/ - jx9_result_string_format(pCtx, "%2d", pTm->tm_mday); - break; - case 'd': - /* Two-digit day of the month (with leading zeros) */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_mon+1); - break; - case 'j': - /*The day of the year, 3 digits with leading zeros*/ - jx9_result_string_format(pCtx, "%03d", pTm->tm_yday); - break; - case 'u': - /* ISO-8601 numeric representation of the day of the week */ - jx9_result_string_format(pCtx, "%d", aISO8601[pTm->tm_wday % 7 ]); - break; - case 'w': - /* Numeric representation of the day of the week */ - jx9_result_string_format(pCtx, "%d", pTm->tm_wday); - break; - case 'b': - case 'h': - /*A short textual representation of a month, three letters (Not based on locale)*/ - jx9_result_string(pCtx, SyTimeGetMonth(pTm->tm_mon), (int)sizeof(char)*3); - break; - case 'B': - /* Full month name (Not based on locale) */ - jx9_result_string(pCtx, SyTimeGetMonth(pTm->tm_mon), -1/*Compute length automatically*/); - break; - case 'm': - /*Numeric representation of a month, with leading zeros*/ - jx9_result_string_format(pCtx, "%02d", pTm->tm_mon + 1); - break; - case 'C': - /* Two digit representation of the century */ - jx9_result_string_format(pCtx, "%2d", pTm->tm_year/100); - break; - case 'y': - case 'g': - /* Two digit representation of the year */ - jx9_result_string_format(pCtx, "%2d", pTm->tm_year%100); - break; - case 'Y': - case 'G': - /* Four digit representation of the year */ - jx9_result_string_format(pCtx, "%4d", pTm->tm_year); - break; - case 'I': - /* 12-hour format of an hour with leading zeros */ - jx9_result_string_format(pCtx, "%02d", 1+(pTm->tm_hour%12)); - break; - case 'l': - /* 12-hour format of an hour with leading space */ - jx9_result_string_format(pCtx, "%2d", 1+(pTm->tm_hour%12)); - break; - case 'H': - /* 24-hour format of an hour with leading zeros */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_hour); - break; - case 'M': - /* Minutes with leading zeros */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_min); - break; - case 'S': - /* Seconds with leading zeros */ - jx9_result_string_format(pCtx, "%02d", pTm->tm_sec); - break; - case 'z': - case 'Z': - /* Timezone identifier */ - zCur = pTm->tm_zone; - if( zCur == 0 ){ - /* Assume GMT */ - zCur = "GMT"; - } - jx9_result_string(pCtx, zCur, -1); - break; - case 'T': - case 'X': - /* Same as "%H:%M:%S" */ - jx9_result_string_format(pCtx, "%02d:%02d:%02d", pTm->tm_hour, pTm->tm_min, pTm->tm_sec); - break; - case 'R': - /* Same as "%H:%M" */ - jx9_result_string_format(pCtx, "%02d:%02d", pTm->tm_hour, pTm->tm_min); - break; - case 'P': - /* Lowercase Ante meridiem and Post meridiem */ - jx9_result_string(pCtx, pTm->tm_hour > 12 ? "pm" : "am", (int)sizeof(char)*2); - break; - case 'p': - /* Uppercase Ante meridiem and Post meridiem */ - jx9_result_string(pCtx, pTm->tm_hour > 12 ? "PM" : "AM", (int)sizeof(char)*2); - break; - case 'r': - /* Same as "%I:%M:%S %p" */ - jx9_result_string_format(pCtx, "%02d:%02d:%02d %s", - 1+(pTm->tm_hour%12), - pTm->tm_min, - pTm->tm_sec, - pTm->tm_hour > 12 ? "PM" : "AM" - ); - break; - case 'D': - case 'x': - /* Same as "%m/%d/%y" */ - jx9_result_string_format(pCtx, "%02d/%02d/%02d", - pTm->tm_mon+1, - pTm->tm_mday, - pTm->tm_year%100 - ); - break; - case 'F': - /* Same as "%Y-%m-%d" */ - jx9_result_string_format(pCtx, "%d-%02d-%02d", - pTm->tm_year, - pTm->tm_mon+1, - pTm->tm_mday - ); - break; - case 'c': - jx9_result_string_format(pCtx, "%d-%02d-%02d %02d:%02d:%02d", - pTm->tm_year, - pTm->tm_mon+1, - pTm->tm_mday, - pTm->tm_hour, - pTm->tm_min, - pTm->tm_sec - ); - break; - case 's':{ - time_t tt; - /* Seconds since the Unix Epoch */ - time(&tt); - jx9_result_string_format(pCtx, "%u", (unsigned int)tt); - break; - } - default: - /* unknown specifer, simply ignore*/ - break; - } - /* Advance the cursor */ - zIn++; - } - return SXRET_OK; -} -/* - * string date(string $format [, int $timestamp = time() ] ) - * Returns a string formatted according to the given format string using - * the given integer timestamp or the current time if no timestamp is given. - * In other words, timestamp is optional and defaults to the value of time(). - * Parameters - * $format - * The format of the outputted date string (See code above) - * $timestamp - * The optional timestamp parameter is an integer Unix timestamp - * that defaults to the current local time if a timestamp is not given. - * In other words, it defaults to the value of time(). - * Return - * A formatted date string. If a non-numeric value is used for timestamp, FALSE is returned. - */ -static int jx9Builtin_date(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFormat; - int nLen; - Sytm sTm; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Don't bother processing return the empty string */ - jx9_result_string(pCtx, "", 0); - } - if( nArg < 2 ){ -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - }else{ - /* Use the given timestamp */ - time_t t; - struct tm *pTm; - if( jx9_value_is_int(apArg[1]) ){ - t = (time_t)jx9_value_to_int64(apArg[1]); - pTm = localtime(&t); - if( pTm == 0 ){ - time(&t); - } - }else{ - time(&t); - } - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); - } - /* Format the given string */ - DateFormat(pCtx, zFormat, nLen, &sTm); - return JX9_OK; -} -/* - * string strftime(string $format [, int $timestamp = time() ] ) - * Format a local time/date (PLATFORM INDEPENDANT IMPLEENTATION NOT BASED ON LOCALE) - * Parameters - * $format - * The format of the outputted date string (See code above) - * $timestamp - * The optional timestamp parameter is an integer Unix timestamp - * that defaults to the current local time if a timestamp is not given. - * In other words, it defaults to the value of time(). - * Return - * Returns a string formatted according format using the given timestamp - * or the current local time if no timestamp is given. - */ -static int jx9Builtin_strftime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFormat; - int nLen; - Sytm sTm; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Don't bother processing return FALSE */ - jx9_result_bool(pCtx, 0); - } - if( nArg < 2 ){ -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - }else{ - /* Use the given timestamp */ - time_t t; - struct tm *pTm; - if( jx9_value_is_int(apArg[1]) ){ - t = (time_t)jx9_value_to_int64(apArg[1]); - pTm = localtime(&t); - if( pTm == 0 ){ - time(&t); - } - }else{ - time(&t); - } - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); - } - /* Format the given string */ - jx9Strftime(pCtx, zFormat, nLen, &sTm); - if( jx9_context_result_buf_length(pCtx) < 1 ){ - /* Nothing was formatted, return FALSE */ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * string gmdate(string $format [, int $timestamp = time() ] ) - * Identical to the date() function except that the time returned - * is Greenwich Mean Time (GMT). - * Parameters - * $format - * The format of the outputted date string (See code above) - * $timestamp - * The optional timestamp parameter is an integer Unix timestamp - * that defaults to the current local time if a timestamp is not given. - * In other words, it defaults to the value of time(). - * Return - * A formatted date string. If a non-numeric value is used for timestamp, FALSE is returned. - */ -static int jx9Builtin_gmdate(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFormat; - int nLen; - Sytm sTm; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Don't bother processing return the empty string */ - jx9_result_string(pCtx, "", 0); - } - if( nArg < 2 ){ -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = gmtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - }else{ - /* Use the given timestamp */ - time_t t; - struct tm *pTm; - if( jx9_value_is_int(apArg[1]) ){ - t = (time_t)jx9_value_to_int64(apArg[1]); - pTm = gmtime(&t); - if( pTm == 0 ){ - time(&t); - } - }else{ - time(&t); - } - pTm = gmtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); - } - /* Format the given string */ - DateFormat(pCtx, zFormat, nLen, &sTm); - return JX9_OK; -} -/* - * array localtime([ int $timestamp = time() [, bool $is_associative = false ]]) - * Return the local time. - * Parameter - * $timestamp: The optional timestamp parameter is an integer Unix timestamp - * that defaults to the current local time if a timestamp is not given. - * In other words, it defaults to the value of time(). - * $is_associative - * If set to FALSE or not supplied then the array is returned as a regular, numerically - * indexed array. If the argument is set to TRUE then localtime() returns an associative - * array containing all the different elements of the structure returned by the C function - * call to localtime. The names of the different keys of the associative array are as follows: - * "tm_sec" - seconds, 0 to 59 - * "tm_min" - minutes, 0 to 59 - * "tm_hour" - hours, 0 to 23 - * "tm_mday" - day of the month, 1 to 31 - * "tm_mon" - month of the year, 0 (Jan) to 11 (Dec) - * "tm_year" - years since 1900 - * "tm_wday" - day of the week, 0 (Sun) to 6 (Sat) - * "tm_yday" - day of the year, 0 to 365 - * "tm_isdst" - is daylight savings time in effect? Positive if yes, 0 if not, negative if unknown. - * Returns - * An associative array of information related to the timestamp. - */ -static int jx9Builtin_localtime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pValue, *pArray; - int isAssoc = 0; - Sytm sTm; - if( nArg < 1 ){ -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); /* TODO(chems): GMT not local */ - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - }else{ - /* Use the given timestamp */ - time_t t; - struct tm *pTm; - if( jx9_value_is_int(apArg[0]) ){ - t = (time_t)jx9_value_to_int64(apArg[0]); - pTm = localtime(&t); - if( pTm == 0 ){ - time(&t); - } - }else{ - time(&t); - } - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); - } - /* Element value */ - pValue = jx9_context_new_scalar(pCtx); - if( pValue == 0 ){ - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - if( nArg > 1 ){ - isAssoc = jx9_value_to_bool(apArg[1]); - } - /* Fill the array */ - /* Seconds */ - jx9_value_int(pValue, sTm.tm_sec); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_sec", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* Minutes */ - jx9_value_int(pValue, sTm.tm_min); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_min", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* Hours */ - jx9_value_int(pValue, sTm.tm_hour); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_hour", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* mday */ - jx9_value_int(pValue, sTm.tm_mday); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_mday", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* mon */ - jx9_value_int(pValue, sTm.tm_mon); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_mon", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* year since 1900 */ - jx9_value_int(pValue, sTm.tm_year-1900); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_year", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* wday */ - jx9_value_int(pValue, sTm.tm_wday); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_wday", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* yday */ - jx9_value_int(pValue, sTm.tm_yday); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_yday", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* isdst */ -#ifdef __WINNT__ -#ifdef _MSC_VER -#ifndef _WIN32_WCE - _get_daylight(&sTm.tm_isdst); -#endif -#endif -#endif - jx9_value_int(pValue, sTm.tm_isdst); - if( isAssoc ){ - jx9_array_add_strkey_elem(pArray, "tm_isdst", pValue); - }else{ - jx9_array_add_elem(pArray, 0/* Automatic index */, pValue); - } - /* Return the array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * int idate(string $format [, int $timestamp = time() ]) - * Returns a number formatted according to the given format string - * using the given integer timestamp or the current local time if - * no timestamp is given. In other words, timestamp is optional and defaults - * to the value of time(). - * Unlike the function date(), idate() accepts just one char in the format - * parameter. - * $Parameters - * Supported format - * d Day of the month - * h Hour (12 hour format) - * H Hour (24 hour format) - * i Minutes - * I (uppercase i)1 if DST is activated, 0 otherwise - * L (uppercase l) returns 1 for leap year, 0 otherwise - * m Month number - * s Seconds - * t Days in current month - * U Seconds since the Unix Epoch - January 1 1970 00:00:00 UTC - this is the same as time() - * w Day of the week (0 on Sunday) - * W ISO-8601 week number of year, weeks starting on Monday - * y Year (1 or 2 digits - check note below) - * Y Year (4 digits) - * z Day of the year - * Z Timezone offset in seconds - * $timestamp - * The optional timestamp parameter is an integer Unix timestamp that defaults - * to the current local time if a timestamp is not given. In other words, it defaults - * to the value of time(). - * Return - * An integer. - */ -static int jx9Builtin_idate(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFormat; - jx9_int64 iVal = 0; - int nLen; - Sytm sTm; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return -1 */ - jx9_result_int(pCtx, -1); - return JX9_OK; - } - zFormat = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Don't bother processing return -1*/ - jx9_result_int(pCtx, -1); - } - if( nArg < 2 ){ -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - }else{ - /* Use the given timestamp */ - time_t t; - struct tm *pTm; - if( jx9_value_is_int(apArg[1]) ){ - t = (time_t)jx9_value_to_int64(apArg[1]); - pTm = localtime(&t); - if( pTm == 0 ){ - time(&t); - } - }else{ - time(&t); - } - pTm = localtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); - } - /* Perform the requested operation */ - switch(zFormat[0]){ - case 'd': - /* Day of the month */ - iVal = sTm.tm_mday; - break; - case 'h': - /* Hour (12 hour format)*/ - iVal = 1 + (sTm.tm_hour % 12); - break; - case 'H': - /* Hour (24 hour format)*/ - iVal = sTm.tm_hour; - break; - case 'i': - /*Minutes*/ - iVal = sTm.tm_min; - break; - case 'I': - /* returns 1 if DST is activated, 0 otherwise */ -#ifdef __WINNT__ -#ifdef _MSC_VER -#ifndef _WIN32_WCE - _get_daylight(&sTm.tm_isdst); -#endif -#endif -#endif - iVal = sTm.tm_isdst; - break; - case 'L': - /* returns 1 for leap year, 0 otherwise */ - iVal = IS_LEAP_YEAR(sTm.tm_year); - break; - case 'm': - /* Month number*/ - iVal = sTm.tm_mon; - break; - case 's': - /*Seconds*/ - iVal = sTm.tm_sec; - break; - case 't':{ - /*Days in current month*/ - static const int aMonDays[] = {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; - int nDays = aMonDays[sTm.tm_mon % 12 ]; - if( sTm.tm_mon == 1 /* 'February' */ && !IS_LEAP_YEAR(sTm.tm_year) ){ - nDays = 28; - } - iVal = nDays; - break; - } - case 'U': - /*Seconds since the Unix Epoch*/ - iVal = (jx9_int64)time(0); - break; - case 'w': - /* Day of the week (0 on Sunday) */ - iVal = sTm.tm_wday; - break; - case 'W': { - /* ISO-8601 week number of year, weeks starting on Monday */ - static const int aISO8601[] = { 7 /* Sunday */, 1 /* Monday */, 2, 3, 4, 5, 6 }; - iVal = aISO8601[sTm.tm_wday % 7 ]; - break; - } - case 'y': - /* Year (2 digits) */ - iVal = sTm.tm_year % 100; - break; - case 'Y': - /* Year (4 digits) */ - iVal = sTm.tm_year; - break; - case 'z': - /* Day of the year */ - iVal = sTm.tm_yday; - break; - case 'Z': - /*Timezone offset in seconds*/ - iVal = sTm.tm_gmtoff; - break; - default: - /* unknown format, throw a warning */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Unknown date format token"); - break; - } - /* Return the time value */ - jx9_result_int64(pCtx, iVal); - return JX9_OK; -} -/* - * int mktime/gmmktime([ int $hour = date("H") [, int $minute = date("i") [, int $second = date("s") - * [, int $month = date("n") [, int $day = date("j") [, int $year = date("Y") [, int $is_dst = -1 ]]]]]]] ) - * Returns the Unix timestamp corresponding to the arguments given. This timestamp is a 64bit integer - * containing the number of seconds between the Unix Epoch (January 1 1970 00:00:00 GMT) and the time - * specified. - * Arguments may be left out in order from right to left; any arguments thus omitted will be set to - * the current value according to the local date and time. - * Parameters - * $hour - * The number of the hour relevant to the start of the day determined by month, day and year. - * Negative values reference the hour before midnight of the day in question. Values greater - * than 23 reference the appropriate hour in the following day(s). - * $minute - * The number of the minute relevant to the start of the hour. Negative values reference - * the minute in the previous hour. Values greater than 59 reference the appropriate minute - * in the following hour(s). - * $second - * The number of seconds relevant to the start of the minute. Negative values reference - * the second in the previous minute. Values greater than 59 reference the appropriate - * second in the following minute(s). - * $month - * The number of the month relevant to the end of the previous year. Values 1 to 12 reference - * the normal calendar months of the year in question. Values less than 1 (including negative values) - * reference the months in the previous year in reverse order, so 0 is December, -1 is November)... - * $day - * The number of the day relevant to the end of the previous month. Values 1 to 28, 29, 30 or 31 - * (depending upon the month) reference the normal days in the relevant month. Values less than 1 - * (including negative values) reference the days in the previous month, so 0 is the last day - * of the previous month, -1 is the day before that, etc. Values greater than the number of days - * in the relevant month reference the appropriate day in the following month(s). - * $year - * The number of the year, may be a two or four digit value, with values between 0-69 mapping - * to 2000-2069 and 70-100 to 1970-2000. On systems where time_t is a 32bit signed integer, as - * most common today, the valid range for year is somewhere between 1901 and 2038. - * $is_dst - * This parameter can be set to 1 if the time is during daylight savings time (DST), 0 if it is not, - * or -1 (the default) if it is unknown whether the time is within daylight savings time or not. - * Return - * mktime() returns the Unix timestamp of the arguments given. - * If the arguments are invalid, the function returns FALSE - */ -static int jx9Builtin_mktime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFunction; - jx9_int64 iVal = 0; - struct tm *pTm; - time_t t; - /* Extract function name */ - zFunction = jx9_function_name(pCtx); - /* Get the current time */ - time(&t); - if( zFunction[0] == 'g' /* gmmktime */ ){ - pTm = gmtime(&t); - }else{ - /* localtime */ - pTm = localtime(&t); - } - if( nArg > 0 ){ - int iVal; - /* Hour */ - iVal = jx9_value_to_int(apArg[0]); - pTm->tm_hour = iVal; - if( nArg > 1 ){ - /* Minutes */ - iVal = jx9_value_to_int(apArg[1]); - pTm->tm_min = iVal; - if( nArg > 2 ){ - /* Seconds */ - iVal = jx9_value_to_int(apArg[2]); - pTm->tm_sec = iVal; - if( nArg > 3 ){ - /* Month */ - iVal = jx9_value_to_int(apArg[3]); - pTm->tm_mon = iVal - 1; - if( nArg > 4 ){ - /* mday */ - iVal = jx9_value_to_int(apArg[4]); - pTm->tm_mday = iVal; - if( nArg > 5 ){ - /* Year */ - iVal = jx9_value_to_int(apArg[5]); - if( iVal > 1900 ){ - iVal -= 1900; - } - pTm->tm_year = iVal; - if( nArg > 6 ){ - /* is_dst */ - iVal = jx9_value_to_bool(apArg[6]); - pTm->tm_isdst = iVal; - } - } - } - } - } - } - } - /* Make the time */ - iVal = (jx9_int64)mktime(pTm); - /* Return the timesatmp as a 64bit integer */ - jx9_result_int64(pCtx, iVal); - return JX9_OK; -} -/* - * Section: - * URL handling Functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * Output consumer callback for the standard Symisc routines. - * [i.e: SyBase64Encode(), SyBase64Decode(), SyUriEncode(), ...]. - */ -static int Consumer(const void *pData, unsigned int nLen, void *pUserData) -{ - /* Store in the call context result buffer */ - jx9_result_string((jx9_context *)pUserData, (const char *)pData, (int)nLen); - return SXRET_OK; -} -/* - * string base64_encode(string $data) - * string convert_uuencode(string $data) - * Encodes data with MIME base64 - * Parameter - * $data - * Data to encode - * Return - * Encoded data or FALSE on failure. - */ -static int jx9Builtin_base64_encode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the input string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Nothing to process, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the BASE64 encoding */ - SyBase64Encode(zIn, (sxu32)nLen, Consumer, pCtx); - return JX9_OK; -} -/* - * string base64_decode(string $data) - * string convert_uudecode(string $data) - * Decodes data encoded with MIME base64 - * Parameter - * $data - * Encoded data. - * Return - * Returns the original data or FALSE on failure. - */ -static int jx9Builtin_base64_decode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the input string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Nothing to process, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the BASE64 decoding */ - SyBase64Decode(zIn, (sxu32)nLen, Consumer, pCtx); - return JX9_OK; -} -/* - * string urlencode(string $str) - * URL encoding - * Parameter - * $data - * Input string. - * Return - * Returns a string in which all non-alphanumeric characters except -_. have - * been replaced with a percent (%) sign followed by two hex digits and spaces - * encoded as plus (+) signs. - */ -static int jx9Builtin_urlencode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the input string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Nothing to process, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the URL encoding */ - SyUriEncode(zIn, (sxu32)nLen, Consumer, pCtx); - return JX9_OK; -} -/* - * string urldecode(string $str) - * Decodes any %## encoding in the given string. - * Plus symbols ('+') are decoded to a space character. - * Parameter - * $data - * Input string. - * Return - * Decoded URL or FALSE on failure. - */ -static int jx9Builtin_urldecode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn; - int nLen; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the input string */ - zIn = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Nothing to process, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the URL decoding */ - SyUriDecode(zIn, (sxu32)nLen, Consumer, pCtx, TRUE); - return JX9_OK; -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* Table of the built-in functions */ -static const jx9_builtin_func aBuiltInFunc[] = { - /* Variable handling functions */ - { "is_bool" , jx9Builtin_is_bool }, - { "is_float" , jx9Builtin_is_float }, - { "is_real" , jx9Builtin_is_float }, - { "is_double" , jx9Builtin_is_float }, - { "is_int" , jx9Builtin_is_int }, - { "is_integer" , jx9Builtin_is_int }, - { "is_long" , jx9Builtin_is_int }, - { "is_string" , jx9Builtin_is_string }, - { "is_null" , jx9Builtin_is_null }, - { "is_numeric" , jx9Builtin_is_numeric }, - { "is_scalar" , jx9Builtin_is_scalar }, - { "is_array" , jx9Builtin_is_array }, - { "is_object" , jx9Builtin_is_object }, - { "is_resource", jx9Builtin_is_resource }, - { "douleval" , jx9Builtin_floatval }, - { "floatval" , jx9Builtin_floatval }, - { "intval" , jx9Builtin_intval }, - { "strval" , jx9Builtin_strval }, - { "empty" , jx9Builtin_empty }, -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifdef JX9_ENABLE_MATH_FUNC - /* Math functions */ - { "abs" , jx9Builtin_abs }, - { "sqrt" , jx9Builtin_sqrt }, - { "exp" , jx9Builtin_exp }, - { "floor", jx9Builtin_floor }, - { "cos" , jx9Builtin_cos }, - { "sin" , jx9Builtin_sin }, - { "acos" , jx9Builtin_acos }, - { "asin" , jx9Builtin_asin }, - { "cosh" , jx9Builtin_cosh }, - { "sinh" , jx9Builtin_sinh }, - { "ceil" , jx9Builtin_ceil }, - { "tan" , jx9Builtin_tan }, - { "tanh" , jx9Builtin_tanh }, - { "atan" , jx9Builtin_atan }, - { "atan2", jx9Builtin_atan2 }, - { "log" , jx9Builtin_log }, - { "log10" , jx9Builtin_log10 }, - { "pow" , jx9Builtin_pow }, - { "pi", jx9Builtin_pi }, - { "fmod", jx9Builtin_fmod }, - { "hypot", jx9Builtin_hypot }, -#endif /* JX9_ENABLE_MATH_FUNC */ - { "round", jx9Builtin_round }, - { "dechex", jx9Builtin_dechex }, - { "decoct", jx9Builtin_decoct }, - { "decbin", jx9Builtin_decbin }, - { "hexdec", jx9Builtin_hexdec }, - { "bindec", jx9Builtin_bindec }, - { "octdec", jx9Builtin_octdec }, - { "base_convert", jx9Builtin_base_convert }, - /* String handling functions */ - { "substr", jx9Builtin_substr }, - { "substr_compare", jx9Builtin_substr_compare }, - { "substr_count", jx9Builtin_substr_count }, - { "chunk_split", jx9Builtin_chunk_split}, - { "htmlspecialchars", jx9Builtin_htmlspecialchars }, - { "htmlspecialchars_decode", jx9Builtin_htmlspecialchars_decode }, - { "get_html_translation_table", jx9Builtin_get_html_translation_table }, - { "htmlentities", jx9Builtin_htmlentities}, - { "html_entity_decode", jx9Builtin_html_entity_decode}, - { "strlen" , jx9Builtin_strlen }, - { "strcmp" , jx9Builtin_strcmp }, - { "strcoll" , jx9Builtin_strcmp }, - { "strncmp" , jx9Builtin_strncmp }, - { "strcasecmp" , jx9Builtin_strcasecmp }, - { "strncasecmp", jx9Builtin_strncasecmp}, - { "implode" , jx9Builtin_implode }, - { "join" , jx9Builtin_implode }, - { "implode_recursive" , jx9Builtin_implode_recursive }, - { "join_recursive" , jx9Builtin_implode_recursive }, - { "explode" , jx9Builtin_explode }, - { "trim" , jx9Builtin_trim }, - { "rtrim" , jx9Builtin_rtrim }, - { "chop" , jx9Builtin_rtrim }, - { "ltrim" , jx9Builtin_ltrim }, - { "strtolower", jx9Builtin_strtolower }, - { "mb_strtolower", jx9Builtin_strtolower }, /* Only UTF-8 encoding is supported */ - { "strtoupper", jx9Builtin_strtoupper }, - { "mb_strtoupper", jx9Builtin_strtoupper }, /* Only UTF-8 encoding is supported */ - { "ord", jx9Builtin_ord }, - { "chr", jx9Builtin_chr }, - { "bin2hex", jx9Builtin_bin2hex }, - { "strstr", jx9Builtin_strstr }, - { "stristr", jx9Builtin_stristr }, - { "strchr", jx9Builtin_strstr }, - { "strpos", jx9Builtin_strpos }, - { "stripos", jx9Builtin_stripos }, - { "strrpos", jx9Builtin_strrpos }, - { "strripos", jx9Builtin_strripos }, - { "strrchr", jx9Builtin_strrchr }, - { "strrev", jx9Builtin_strrev }, - { "str_repeat", jx9Builtin_str_repeat }, - { "nl2br", jx9Builtin_nl2br }, - { "sprintf", jx9Builtin_sprintf }, - { "printf", jx9Builtin_printf }, - { "vprintf", jx9Builtin_vprintf }, - { "vsprintf", jx9Builtin_vsprintf }, - { "size_format", jx9Builtin_size_format}, -#if !defined(JX9_DISABLE_HASH_FUNC) - { "md5", jx9Builtin_md5 }, - { "sha1", jx9Builtin_sha1 }, - { "crc32", jx9Builtin_crc32 }, -#endif /* JX9_DISABLE_HASH_FUNC */ - { "str_getcsv", jx9Builtin_str_getcsv }, - { "strip_tags", jx9Builtin_strip_tags }, - { "str_split", jx9Builtin_str_split }, - { "strspn", jx9Builtin_strspn }, - { "strcspn", jx9Builtin_strcspn }, - { "strpbrk", jx9Builtin_strpbrk }, - { "soundex", jx9Builtin_soundex }, - { "wordwrap", jx9Builtin_wordwrap }, - { "strtok", jx9Builtin_strtok }, - { "str_pad", jx9Builtin_str_pad }, - { "str_replace", jx9Builtin_str_replace}, - { "str_ireplace", jx9Builtin_str_replace}, - { "strtr", jx9Builtin_strtr }, - { "parse_ini_string", jx9Builtin_parse_ini_string}, - /* Ctype functions */ - { "ctype_alnum", jx9Builtin_ctype_alnum }, - { "ctype_alpha", jx9Builtin_ctype_alpha }, - { "ctype_cntrl", jx9Builtin_ctype_cntrl }, - { "ctype_digit", jx9Builtin_ctype_digit }, - { "ctype_xdigit", jx9Builtin_ctype_xdigit}, - { "ctype_graph", jx9Builtin_ctype_graph }, - { "ctype_print", jx9Builtin_ctype_print }, - { "ctype_punct", jx9Builtin_ctype_punct }, - { "ctype_space", jx9Builtin_ctype_space }, - { "ctype_lower", jx9Builtin_ctype_lower }, - { "ctype_upper", jx9Builtin_ctype_upper }, - /* Time functions */ - { "time" , jx9Builtin_time }, - { "microtime", jx9Builtin_microtime }, - { "getdate" , jx9Builtin_getdate }, - { "gettimeofday", jx9Builtin_gettimeofday }, - { "date", jx9Builtin_date }, - { "strftime", jx9Builtin_strftime }, - { "idate", jx9Builtin_idate }, - { "gmdate", jx9Builtin_gmdate }, - { "localtime", jx9Builtin_localtime }, - { "mktime", jx9Builtin_mktime }, - { "gmmktime", jx9Builtin_mktime }, - /* URL functions */ - { "base64_encode", jx9Builtin_base64_encode }, - { "base64_decode", jx9Builtin_base64_decode }, - { "convert_uuencode", jx9Builtin_base64_encode }, - { "convert_uudecode", jx9Builtin_base64_decode }, - { "urlencode", jx9Builtin_urlencode }, - { "urldecode", jx9Builtin_urldecode }, - { "rawurlencode", jx9Builtin_urlencode }, - { "rawurldecode", jx9Builtin_urldecode }, -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -}; -/* - * Register the built-in functions defined above, the array functions - * defined in hashmap.c and the IO functions defined in vfs.c. - */ -JX9_PRIVATE void jx9RegisterBuiltInFunction(jx9_vm *pVm) -{ - sxu32 n; - for( n = 0 ; n < SX_ARRAYSIZE(aBuiltInFunc) ; ++n ){ - jx9_create_function(&(*pVm), aBuiltInFunc[n].zName, aBuiltInFunc[n].xFunc, 0); - } - /* Register hashmap functions [i.e: sort(), count(), array_diff(), ...] */ - jx9RegisterHashmapFunctions(&(*pVm)); - /* Register IO functions [i.e: fread(), fwrite(), chdir(), mkdir(), file(), ...] */ - jx9RegisterIORoutine(&(*pVm)); -} - -/* - * ---------------------------------------------------------- - * File: jx9_compile.c - * MD5: 562e73eb7214f890e71713c6b97a7863 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: compile.c v1.7 FreeBSD 2012-12-11 21:46 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* - * This file implement a thread-safe and full-reentrant compiler for the JX9 engine. - * That is, routines defined in this file takes a stream of tokens and output - * JX9 bytecode instructions. - */ -/* Forward declaration */ -typedef struct LangConstruct LangConstruct; -typedef struct JumpFixup JumpFixup; -/* Block [i.e: set of statements] control flags */ -#define GEN_BLOCK_LOOP 0x001 /* Loop block [i.e: for, while, ...] */ -#define GEN_BLOCK_PROTECTED 0x002 /* Protected block */ -#define GEN_BLOCK_COND 0x004 /* Conditional block [i.e: if(condition){} ]*/ -#define GEN_BLOCK_FUNC 0x008 /* Function body */ -#define GEN_BLOCK_GLOBAL 0x010 /* Global block (always set)*/ -#define GEN_BLOC_NESTED_FUNC 0x020 /* Nested function body */ -#define GEN_BLOCK_EXPR 0x040 /* Expression */ -#define GEN_BLOCK_STD 0x080 /* Standard block */ -#define GEN_BLOCK_SWITCH 0x100 /* Switch statement */ -/* - * Compilation of some JX9 constructs such as if, for, while, the logical or - * (||) and logical and (&&) operators in expressions requires the - * generation of forward jumps. - * Since the destination PC target of these jumps isn't known when the jumps - * are emitted, we record each forward jump in an instance of the following - * structure. Those jumps are fixed later when the jump destination is resolved. - */ -struct JumpFixup -{ - sxi32 nJumpType; /* Jump type. Either TRUE jump, FALSE jump or Unconditional jump */ - sxu32 nInstrIdx; /* Instruction index to fix later when the jump destination is resolved. */ -}; -/* - * Each language construct is represented by an instance - * of the following structure. - */ -struct LangConstruct -{ - sxu32 nID; /* Language construct ID [i.e: JX9_TKWRD_WHILE, JX9_TKWRD_FOR, JX9_TKWRD_IF...] */ - ProcLangConstruct xConstruct; /* C function implementing the language construct */ -}; -/* Compilation flags */ -#define JX9_COMPILE_SINGLE_STMT 0x001 /* Compile a single statement */ -/* Token stream synchronization macros */ -#define SWAP_TOKEN_STREAM(GEN, START, END)\ - pTmp = GEN->pEnd;\ - pGen->pIn = START;\ - pGen->pEnd = END -#define UPDATE_TOKEN_STREAM(GEN)\ - if( GEN->pIn < pTmp ){\ - GEN->pIn++;\ - }\ - GEN->pEnd = pTmp -#define SWAP_DELIMITER(GEN, START, END)\ - pTmpIn = GEN->pIn;\ - pTmpEnd = GEN->pEnd;\ - GEN->pIn = START;\ - GEN->pEnd = END -#define RE_SWAP_DELIMITER(GEN)\ - GEN->pIn = pTmpIn;\ - GEN->pEnd = pTmpEnd -/* Flags related to expression compilation */ -#define EXPR_FLAG_LOAD_IDX_STORE 0x001 /* Set the iP2 flag when dealing with the LOAD_IDX instruction */ -#define EXPR_FLAG_RDONLY_LOAD 0x002 /* Read-only load, refer to the 'JX9_OP_LOAD' VM instruction for more information */ -#define EXPR_FLAG_COMMA_STATEMENT 0x004 /* Treat comma expression as a single statement (used by object attributes) */ -/* Forward declaration */ -static sxi32 jx9CompileExpr( - jx9_gen_state *pGen, /* Code generator state */ - sxi32 iFlags, /* Control flags */ - sxi32 (*xTreeValidator)(jx9_gen_state *, jx9_expr_node *) /* Node validator callback.NULL otherwise */ - ); - -/* - * Recover from a compile-time error. In other words synchronize - * the token stream cursor with the first semi-colon seen. - */ -static sxi32 jx9ErrorRecover(jx9_gen_state *pGen) -{ - /* Synchronize with the next-semi-colon and avoid compiling this erroneous statement */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI /*';'*/) == 0){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Check if the given identifier name is reserved or not. - * Return TRUE if reserved.FALSE otherwise. - */ -static int GenStateIsReservedID(SyString *pName) -{ - if( pName->nByte == sizeof("null") - 1 ){ - if( SyStrnicmp(pName->zString, "null", sizeof("null")-1) == 0 ){ - return TRUE; - }else if( SyStrnicmp(pName->zString, "true", sizeof("true")-1) == 0 ){ - return TRUE; - } - }else if( pName->nByte == sizeof("false") - 1 ){ - if( SyStrnicmp(pName->zString, "false", sizeof("false")-1) == 0 ){ - return TRUE; - } - } - /* Not a reserved constant */ - return FALSE; -} -/* - * Check if a given token value is installed in the literal table. - */ -static sxi32 GenStateFindLiteral(jx9_gen_state *pGen, const SyString *pValue, sxu32 *pIdx) -{ - SyHashEntry *pEntry; - pEntry = SyHashGet(&pGen->hLiteral, (const void *)pValue->zString, pValue->nByte); - if( pEntry == 0 ){ - return SXERR_NOTFOUND; - } - *pIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); - return SXRET_OK; -} -/* - * Install a given constant index in the literal table. - * In order to be installed, the jx9_value must be of type string. - */ -static sxi32 GenStateInstallLiteral(jx9_gen_state *pGen,jx9_value *pObj, sxu32 nIdx) -{ - if( SyBlobLength(&pObj->sBlob) > 0 ){ - SyHashInsert(&pGen->hLiteral, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob), SX_INT_TO_PTR(nIdx)); - } - return SXRET_OK; -} -/* - * Generate a fatal error. - */ -static sxi32 GenStateOutOfMem(jx9_gen_state *pGen) -{ - jx9GenCompileError(pGen,E_ERROR,1,"Fatal, Jx9 compiler is running out of memory"); - /* Abort compilation immediately */ - return SXERR_ABORT; -} -/* - * Fetch a block that correspond to the given criteria from the stack of - * compiled blocks. - * Return a pointer to that block on success. NULL otherwise. - */ -static GenBlock * GenStateFetchBlock(GenBlock *pCurrent, sxi32 iBlockType, sxi32 iCount) -{ - GenBlock *pBlock = pCurrent; - for(;;){ - if( pBlock->iFlags & iBlockType ){ - iCount--; /* Decrement nesting level */ - if( iCount < 1 ){ - /* Block meet with the desired criteria */ - return pBlock; - } - } - /* Point to the upper block */ - pBlock = pBlock->pParent; - if( pBlock == 0 || (pBlock->iFlags & (GEN_BLOCK_PROTECTED|GEN_BLOCK_FUNC)) ){ - /* Forbidden */ - break; - } - } - /* No such block */ - return 0; -} -/* - * Initialize a freshly allocated block instance. - */ -static void GenStateInitBlock( - jx9_gen_state *pGen, /* Code generator state */ - GenBlock *pBlock, /* Target block */ - sxi32 iType, /* Block type [i.e: loop, conditional, function body, etc.]*/ - sxu32 nFirstInstr, /* First instruction to compile */ - void *pUserData /* Upper layer private data */ - ) -{ - /* Initialize block fields */ - pBlock->nFirstInstr = nFirstInstr; - pBlock->pUserData = pUserData; - pBlock->pGen = pGen; - pBlock->iFlags = iType; - pBlock->pParent = 0; - pBlock->bPostContinue = 0; - SySetInit(&pBlock->aJumpFix, &pGen->pVm->sAllocator, sizeof(JumpFixup)); - SySetInit(&pBlock->aPostContFix, &pGen->pVm->sAllocator, sizeof(JumpFixup)); -} -/* - * Allocate a new block instance. - * Return SXRET_OK and write a pointer to the new instantiated block - * on success.Otherwise generate a compile-time error and abort - * processing on failure. - */ -static sxi32 GenStateEnterBlock( - jx9_gen_state *pGen, /* Code generator state */ - sxi32 iType, /* Block type [i.e: loop, conditional, function body, etc.]*/ - sxu32 nFirstInstr, /* First instruction to compile */ - void *pUserData, /* Upper layer private data */ - GenBlock **ppBlock /* OUT: instantiated block */ - ) -{ - GenBlock *pBlock; - /* Allocate a new block instance */ - pBlock = (GenBlock *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(GenBlock)); - if( pBlock == 0 ){ - /* If the supplied memory subsystem is so sick that we are unable to allocate - * a tiny chunk of memory, there is no much we can do here. - */ - return GenStateOutOfMem(pGen); - } - /* Zero the structure */ - SyZero(pBlock, sizeof(GenBlock)); - GenStateInitBlock(&(*pGen), pBlock, iType, nFirstInstr, pUserData); - /* Link to the parent block */ - pBlock->pParent = pGen->pCurrent; - /* Mark as the current block */ - pGen->pCurrent = pBlock; - if( ppBlock ){ - /* Write a pointer to the new instance */ - *ppBlock = pBlock; - } - return SXRET_OK; -} -/* - * Release block fields without freeing the whole instance. - */ -static void GenStateReleaseBlock(GenBlock *pBlock) -{ - SySetRelease(&pBlock->aPostContFix); - SySetRelease(&pBlock->aJumpFix); -} -/* - * Release a block. - */ -static void GenStateFreeBlock(GenBlock *pBlock) -{ - jx9_gen_state *pGen = pBlock->pGen; - GenStateReleaseBlock(&(*pBlock)); - /* Free the instance */ - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pBlock); -} -/* - * POP and release a block from the stack of compiled blocks. - */ -static sxi32 GenStateLeaveBlock(jx9_gen_state *pGen, GenBlock **ppBlock) -{ - GenBlock *pBlock = pGen->pCurrent; - if( pBlock == 0 ){ - /* No more block to pop */ - return SXERR_EMPTY; - } - /* Point to the upper block */ - pGen->pCurrent = pBlock->pParent; - if( ppBlock ){ - /* Write a pointer to the popped block */ - *ppBlock = pBlock; - }else{ - /* Safely release the block */ - GenStateFreeBlock(&(*pBlock)); - } - return SXRET_OK; -} -/* - * Emit a forward jump. - * Notes on forward jumps - * Compilation of some JX9 constructs such as if, for, while and the logical or - * (||) and logical and (&&) operators in expressions requires the - * generation of forward jumps. - * Since the destination PC target of these jumps isn't known when the jumps - * are emitted, we record each forward jump in an instance of the following - * structure. Those jumps are fixed later when the jump destination is resolved. - */ -static sxi32 GenStateNewJumpFixup(GenBlock *pBlock, sxi32 nJumpType, sxu32 nInstrIdx) -{ - JumpFixup sJumpFix; - sxi32 rc; - /* Init the JumpFixup structure */ - sJumpFix.nJumpType = nJumpType; - sJumpFix.nInstrIdx = nInstrIdx; - /* Insert in the jump fixup table */ - rc = SySetPut(&pBlock->aJumpFix,(const void *)&sJumpFix); - return rc; -} -/* - * Fix a forward jump now the jump destination is resolved. - * Return the total number of fixed jumps. - * Notes on forward jumps: - * Compilation of some JX9 constructs such as if, for, while and the logical or - * (||) and logical and (&&) operators in expressions requires the - * generation of forward jumps. - * Since the destination PC target of these jumps isn't known when the jumps - * are emitted, we record each forward jump in an instance of the following - * structure.Those jumps are fixed later when the jump destination is resolved. - */ -static sxu32 GenStateFixJumps(GenBlock *pBlock, sxi32 nJumpType, sxu32 nJumpDest) -{ - JumpFixup *aFix; - VmInstr *pInstr; - sxu32 nFixed; - sxu32 n; - /* Point to the jump fixup table */ - aFix = (JumpFixup *)SySetBasePtr(&pBlock->aJumpFix); - /* Fix the desired jumps */ - for( nFixed = n = 0 ; n < SySetUsed(&pBlock->aJumpFix) ; ++n ){ - if( aFix[n].nJumpType < 0 ){ - /* Already fixed */ - continue; - } - if( nJumpType > 0 && aFix[n].nJumpType != nJumpType ){ - /* Not of our interest */ - continue; - } - /* Point to the instruction to fix */ - pInstr = jx9VmGetInstr(pBlock->pGen->pVm, aFix[n].nInstrIdx); - if( pInstr ){ - pInstr->iP2 = nJumpDest; - nFixed++; - /* Mark as fixed */ - aFix[n].nJumpType = -1; - } - } - /* Total number of fixed jumps */ - return nFixed; -} -/* - * Reserve a room for a numeric constant [i.e: 64-bit integer or real number] - * in the constant table. - */ -static jx9_value * GenStateInstallNumLiteral(jx9_gen_state *pGen, sxu32 *pIdx) -{ - jx9_value *pObj; - sxu32 nIdx = 0; /* cc warning */ - /* Reserve a new constant */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - GenStateOutOfMem(pGen); - return 0; - } - *pIdx = nIdx; - /* TODO(chems): Create a numeric table (64bit int keys) same as - * the constant string iterals table [optimization purposes]. - */ - return pObj; -} -/* - * Compile a numeric [i.e: integer or real] literal. - * Notes on the integer type. - * According to the JX9 language reference manual - * Integers can be specified in decimal (base 10), hexadecimal (base 16), octal (base 8) - * or binary (base 2) notation, optionally preceded by a sign (- or +). - * To use octal notation, precede the number with a 0 (zero). To use hexadecimal - * notation precede the number with 0x. To use binary notation precede the number with 0b. - */ -static sxi32 jx9CompileNumLiteral(jx9_gen_state *pGen,sxi32 iCompileFlag) -{ - SyToken *pToken = pGen->pIn; /* Raw token */ - sxu32 nIdx = 0; - if( pToken->nType & JX9_TK_INTEGER ){ - jx9_value *pObj; - sxi64 iValue; - iValue = jx9TokenValueToInt64(&pToken->sData); - pObj = GenStateInstallNumLiteral(&(*pGen), &nIdx); - if( pObj == 0 ){ - SXUNUSED(iCompileFlag); /* cc warning */ - return SXERR_ABORT; - } - jx9MemObjInitFromInt(pGen->pVm, pObj, iValue); - }else{ - /* Real number */ - jx9_value *pObj; - /* Reserve a new constant */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - return GenStateOutOfMem(pGen); - } - jx9MemObjInitFromString(pGen->pVm, pObj, &pToken->sData); - jx9MemObjToReal(pObj); - } - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Compile a nowdoc string. - * According to the JX9 language reference manual: - * - * Nowdocs are to single-quoted strings what heredocs are to double-quoted strings. - * A nowdoc is specified similarly to a heredoc, but no parsing is done inside a nowdoc. - * The construct is ideal for embedding JX9 code or other large blocks of text without the - * need for escaping. It shares some features in common with the SGML - * construct, in that it declares a block of text which is not for parsing. - * A nowdoc is identified with the same <<< sequence used for heredocs, but the identifier - * which follows is enclosed in single quotes, e.g. <<<'EOT'. All the rules for heredoc - * identifiers also apply to nowdoc identifiers, especially those regarding the appearance - * of the closing identifier. - */ -static sxi32 jx9CompileNowdoc(jx9_gen_state *pGen,sxi32 iCompileFlag) -{ - SyString *pStr = &pGen->pIn->sData; /* Constant string literal */ - jx9_value *pObj; - sxu32 nIdx; - nIdx = 0; /* Prevent compiler warning */ - if( pStr->nByte <= 0 ){ - /* Empty string, load NULL */ - jx9VmEmitInstr(pGen->pVm,JX9_OP_LOADC, 0, 0, 0, 0); - return SXRET_OK; - } - /* Reserve a new constant */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "JX9 engine is running out of memory"); - SXUNUSED(iCompileFlag); /* cc warning */ - return SXERR_ABORT; - } - /* No processing is done here, simply a memcpy() operation */ - jx9MemObjInitFromString(pGen->pVm, pObj, pStr); - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Compile a single quoted string. - * According to the JX9 language reference manual: - * - * The simplest way to specify a string is to enclose it in single quotes (the character ' ). - * To specify a literal single quote, escape it with a backslash (\). To specify a literal - * backslash, double it (\\). All other instances of backslash will be treated as a literal - * backslash: this means that the other escape sequences you might be used to, such as \r - * or \n, will be output literally as specified rather than having any special meaning. - * - */ -JX9_PRIVATE sxi32 jx9CompileSimpleString(jx9_gen_state *pGen, sxi32 iCompileFlag) -{ - SyString *pStr = &pGen->pIn->sData; /* Constant string literal */ - const char *zIn, *zCur, *zEnd; - jx9_value *pObj; - sxu32 nIdx; - nIdx = 0; /* Prevent compiler warning */ - /* Delimit the string */ - zIn = pStr->zString; - zEnd = &zIn[pStr->nByte]; - if( zIn > zEnd ){ - /* Empty string, load NULL */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, 0, 0, 0); - return SXRET_OK; - } - if( SXRET_OK == GenStateFindLiteral(&(*pGen), pStr, &nIdx) ){ - /* Already processed, emit the load constant instruction - * and return. - */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - return SXRET_OK; - } - /* Reserve a new constant */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - jx9GenCompileError(&(*pGen), E_ERROR, 1, "JX9 engine is running out of memory"); - SXUNUSED(iCompileFlag); /* cc warning */ - return SXERR_ABORT; - } - jx9MemObjInitFromString(pGen->pVm, pObj, 0); - /* Compile the node */ - for(;;){ - if( zIn >= zEnd ){ - /* End of input */ - break; - } - zCur = zIn; - while( zIn < zEnd && zIn[0] != '\\' ){ - zIn++; - } - if( zIn > zCur ){ - /* Append raw contents*/ - jx9MemObjStringAppend(pObj, zCur, (sxu32)(zIn-zCur)); - } - else - { - jx9MemObjStringAppend(pObj, "", 0); - } - zIn++; - if( zIn < zEnd ){ - if( zIn[0] == '\\' ){ - /* A literal backslash */ - jx9MemObjStringAppend(pObj, "\\", sizeof(char)); - }else if( zIn[0] == '\'' ){ - /* A single quote */ - jx9MemObjStringAppend(pObj, "'", sizeof(char)); - }else{ - /* verbatim copy */ - zIn--; - jx9MemObjStringAppend(pObj, zIn, sizeof(char)*2); - zIn++; - } - } - /* Advance the stream cursor */ - zIn++; - } - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - if( pStr->nByte < 1024 ){ - /* Install in the literal table */ - GenStateInstallLiteral(pGen, pObj, nIdx); - } - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Process variable expression [i.e: "$var", "${var}"] embedded in a double quoted/heredoc string. - * According to the JX9 language reference manual - * When a string is specified in double quotes or with heredoc, variables are parsed within it. - * There are two types of syntax: a simple one and a complex one. The simple syntax is the most - * common and convenient. It provides a way to embed a variable, an array value, or an object - * property in a string with a minimum of effort. - * Simple syntax - * If a dollar sign ($) is encountered, the parser will greedily take as many tokens as possible - * to form a valid variable name. Enclose the variable name in curly braces to explicitly specify - * the end of the name. - * Similarly, an array index or an object property can be parsed. With array indices, the closing - * square bracket (]) marks the end of the index. The same rules apply to object properties - * as to simple variables. - * Complex (curly) syntax - * This isn't called complex because the syntax is complex, but because it allows for the use - * of complex expressions. - * Any scalar variable, array element or object property with a string representation can be - * included via this syntax. Simply write the expression the same way as it would appear outside - * the string, and then wrap it in { and }. Since { can not be escaped, this syntax will only - * be recognised when the $ immediately follows the {. Use {\$ to get a literal {$ - */ -static sxi32 GenStateProcessStringExpression( - jx9_gen_state *pGen, /* Code generator state */ - const char *zIn, /* Raw expression */ - const char *zEnd /* End of the expression */ - ) -{ - SyToken *pTmpIn, *pTmpEnd; - SySet sToken; - sxi32 rc; - /* Initialize the token set */ - SySetInit(&sToken, &pGen->pVm->sAllocator, sizeof(SyToken)); - /* Preallocate some slots */ - SySetAlloc(&sToken, 0x08); - /* Tokenize the text */ - jx9Tokenize(zIn,(sxu32)(zEnd-zIn),&sToken); - /* Swap delimiter */ - pTmpIn = pGen->pIn; - pTmpEnd = pGen->pEnd; - pGen->pIn = (SyToken *)SySetBasePtr(&sToken); - pGen->pEnd = &pGen->pIn[SySetUsed(&sToken)]; - /* Compile the expression */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - /* Restore token stream */ - pGen->pIn = pTmpIn; - pGen->pEnd = pTmpEnd; - /* Release the token set */ - SySetRelease(&sToken); - /* Compilation result */ - return rc; -} -/* - * Reserve a new constant for a double quoted/heredoc string. - */ -static jx9_value * GenStateNewStrObj(jx9_gen_state *pGen,sxi32 *pCount) -{ - jx9_value *pConstObj; - sxu32 nIdx = 0; - /* Reserve a new constant */ - pConstObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pConstObj == 0 ){ - GenStateOutOfMem(&(*pGen)); - return 0; - } - (*pCount)++; - jx9MemObjInitFromString(pGen->pVm, pConstObj, 0); - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - return pConstObj; -} -/* - * Compile a double quoted/heredoc string. - * According to the JX9 language reference manual - * Heredoc - * A third way to delimit strings is the heredoc syntax: <<<. After this operator, an identifier - * is provided, then a newline. The string itself follows, and then the same identifier again - * to close the quotation. - * The closing identifier must begin in the first column of the line. Also, the identifier must - * follow the same naming rules as any other label in JX9: it must contain only alphanumeric - * characters and underscores, and must start with a non-digit character or underscore. - * Warning - * It is very important to note that the line with the closing identifier must contain - * no other characters, except possibly a semicolon (;). That means especially that the identifier - * may not be indented, and there may not be any spaces or tabs before or after the semicolon. - * It's also important to realize that the first character before the closing identifier must - * be a newline as defined by the local operating system. This is \n on UNIX systems, including Mac OS X. - * The closing delimiter (possibly followed by a semicolon) must also be followed by a newline. - * If this rule is broken and the closing identifier is not "clean", it will not be considered a closing - * identifier, and JX9 will continue looking for one. If a proper closing identifier is not found before - * the end of the current file, a parse error will result at the last line. - * Heredocs can not be used for initializing object properties. - * Double quoted - * If the string is enclosed in double-quotes ("), JX9 will interpret more escape sequences for special characters: - * Escaped characters Sequence Meaning - * \n linefeed (LF or 0x0A (10) in ASCII) - * \r carriage return (CR or 0x0D (13) in ASCII) - * \t horizontal tab (HT or 0x09 (9) in ASCII) - * \v vertical tab (VT or 0x0B (11) in ASCII) - * \f form feed (FF or 0x0C (12) in ASCII) - * \\ backslash - * \$ dollar sign - * \" double-quote - * \[0-7]{1, 3} the sequence of characters matching the regular expression is a character in octal notation - * \x[0-9A-Fa-f]{1, 2} the sequence of characters matching the regular expression is a character in hexadecimal notation - * As in single quoted strings, escaping any other character will result in the backslash being printed too. - * The most important feature of double-quoted strings is the fact that variable names will be expanded. - * See string parsing for details. - */ -static sxi32 GenStateCompileString(jx9_gen_state *pGen) -{ - SyString *pStr = &pGen->pIn->sData; /* Raw token value */ - const char *zIn, *zCur, *zEnd; - jx9_value *pObj = 0; - sxi32 iCons; - sxi32 rc; - /* Delimit the string */ - zIn = pStr->zString; - zEnd = &zIn[pStr->nByte]; - if( zIn > zEnd ){ - /* Empty string, load NULL */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, 0, 0, 0); - return SXRET_OK; - } - zCur = 0; - /* Compile the node */ - iCons = 0; - for(;;){ - zCur = zIn; - while( zIn < zEnd && zIn[0] != '\\' ){ - if(zIn[0] == '$' && &zIn[1] < zEnd && - (((unsigned char)zIn[1] >= 0xc0 || SyisAlpha(zIn[1]) || zIn[1] == '_')) ){ - break; - } - zIn++; - } - if( zIn > zCur ){ - if( pObj == 0 ){ - pObj = GenStateNewStrObj(&(*pGen), &iCons); - if( pObj == 0 ){ - return SXERR_ABORT; - } - } - jx9MemObjStringAppend(pObj, zCur, (sxu32)(zIn-zCur)); - } - else - { - if( pObj == 0 ){ - pObj = GenStateNewStrObj(&(*pGen), &iCons); - if( pObj == 0 ){ - return SXERR_ABORT; - } - } - jx9MemObjStringAppend(pObj, "", 0); - } - if( zIn >= zEnd ){ - break; - } - if( zIn[0] == '\\' ){ - const char *zPtr = 0; - sxu32 n; - zIn++; - if( zIn >= zEnd ){ - break; - } - if( pObj == 0 ){ - pObj = GenStateNewStrObj(&(*pGen), &iCons); - if( pObj == 0 ){ - return SXERR_ABORT; - } - } - n = sizeof(char); /* size of conversion */ - switch( zIn[0] ){ - case '$': - /* Dollar sign */ - jx9MemObjStringAppend(pObj, "$", sizeof(char)); - break; - case '\\': - /* A literal backslash */ - jx9MemObjStringAppend(pObj, "\\", sizeof(char)); - break; - case 'a': - /* The "alert" character (BEL)[ctrl+g] ASCII code 7 */ - jx9MemObjStringAppend(pObj, "\a", sizeof(char)); - break; - case 'b': - /* Backspace (BS)[ctrl+h] ASCII code 8 */ - jx9MemObjStringAppend(pObj, "\b", sizeof(char)); - break; - case 'f': - /* Form-feed (FF)[ctrl+l] ASCII code 12 */ - jx9MemObjStringAppend(pObj, "\f", sizeof(char)); - break; - case 'n': - /* Line feed(new line) (LF)[ctrl+j] ASCII code 10 */ - jx9MemObjStringAppend(pObj, "\n", sizeof(char)); - break; - case 'r': - /* Carriage return (CR)[ctrl+m] ASCII code 13 */ - jx9MemObjStringAppend(pObj, "\r", sizeof(char)); - break; - case 't': - /* Horizontal tab (HT)[ctrl+i] ASCII code 9 */ - jx9MemObjStringAppend(pObj, "\t", sizeof(char)); - break; - case 'v': - /* Vertical tab(VT)[ctrl+k] ASCII code 11 */ - jx9MemObjStringAppend(pObj, "\v", sizeof(char)); - break; - case '\'': - /* Single quote */ - jx9MemObjStringAppend(pObj, "'", sizeof(char)); - break; - case '"': - /* Double quote */ - jx9MemObjStringAppend(pObj, "\"", sizeof(char)); - break; - case '0': - /* NUL byte */ - jx9MemObjStringAppend(pObj, "\0", sizeof(char)); - break; - case 'x': - if((unsigned char)zIn[1] < 0xc0 && SyisHex(zIn[1]) ){ - int c; - /* Hex digit */ - c = SyHexToint(zIn[1]) << 4; - if( &zIn[2] < zEnd ){ - c += SyHexToint(zIn[2]); - } - /* Output char */ - jx9MemObjStringAppend(pObj, (const char *)&c, sizeof(char)); - n += sizeof(char) * 2; - }else{ - /* Output literal character */ - jx9MemObjStringAppend(pObj, "x", sizeof(char)); - } - break; - case 'o': - if( &zIn[1] < zEnd && (unsigned char)zIn[1] < 0xc0 && SyisDigit(zIn[1]) && (zIn[1] - '0') < 8 ){ - /* Octal digit stream */ - int c; - c = 0; - zIn++; - for( zPtr = zIn ; zPtr < &zIn[3*sizeof(char)] ; zPtr++ ){ - if( zPtr >= zEnd || (unsigned char)zPtr[0] >= 0xc0 || !SyisDigit(zPtr[0]) || (zPtr[0] - '0') > 7 ){ - break; - } - c = c * 8 + (zPtr[0] - '0'); - } - if ( c > 0 ){ - jx9MemObjStringAppend(pObj, (const char *)&c, sizeof(char)); - } - n = (sxu32)(zPtr-zIn); - }else{ - /* Output literal character */ - jx9MemObjStringAppend(pObj, "o", sizeof(char)); - } - break; - default: - /* Output without a slash */ - jx9MemObjStringAppend(pObj, zIn, sizeof(char)); - break; - } - /* Advance the stream cursor */ - zIn += n; - continue; - } - if( zIn[0] == '{' ){ - /* Curly syntax */ - const char *zExpr; - sxi32 iNest = 1; - zIn++; - zExpr = zIn; - /* Synchronize with the next closing curly braces */ - while( zIn < zEnd ){ - if( zIn[0] == '{' ){ - /* Increment nesting level */ - iNest++; - }else if(zIn[0] == '}' ){ - /* Decrement nesting level */ - iNest--; - if( iNest <= 0 ){ - break; - } - } - zIn++; - } - /* Process the expression */ - rc = GenStateProcessStringExpression(&(*pGen),zExpr,zIn); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - if( rc != SXERR_EMPTY ){ - ++iCons; - } - if( zIn < zEnd ){ - /* Jump the trailing curly */ - zIn++; - } - }else{ - /* Simple syntax */ - const char *zExpr = zIn; - /* Assemble variable name */ - for(;;){ - /* Jump leading dollars */ - while( zIn < zEnd && zIn[0] == '$' ){ - zIn++; - } - for(;;){ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && (SyisAlphaNum(zIn[0]) || zIn[0] == '_' ) ){ - zIn++; - } - if((unsigned char)zIn[0] >= 0xc0 ){ - /* UTF-8 stream */ - zIn++; - while( zIn < zEnd && (((unsigned char)zIn[0] & 0xc0) == 0x80) ){ - zIn++; - } - continue; - } - break; - } - if( zIn >= zEnd ){ - break; - } - if( zIn[0] == '[' ){ - sxi32 iSquare = 1; - zIn++; - while( zIn < zEnd ){ - if( zIn[0] == '[' ){ - iSquare++; - }else if (zIn[0] == ']' ){ - iSquare--; - if( iSquare <= 0 ){ - break; - } - } - zIn++; - } - if( zIn < zEnd ){ - zIn++; - } - break; - }else if( zIn[0] == '.' ){ - /* Member access operator '.' */ - zIn++; - }else{ - break; - } - } - /* Process the expression */ - rc = GenStateProcessStringExpression(&(*pGen),zExpr, zIn); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - if( rc != SXERR_EMPTY ){ - ++iCons; - } - } - /* Invalidate the previously used constant */ - pObj = 0; - }/*for(;;)*/ - if( iCons > 1 ){ - /* Concatenate all compiled constants */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_CAT, iCons, 0, 0, 0); - } - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Compile a double quoted string. - * See the block-comment above for more information. - */ -JX9_PRIVATE sxi32 jx9CompileString(jx9_gen_state *pGen, sxi32 iCompileFlag) -{ - sxi32 rc; - rc = GenStateCompileString(&(*pGen)); - SXUNUSED(iCompileFlag); /* cc warning */ - /* Compilation result */ - return rc; -} -/* - * Compile a literal which is an identifier(name) for simple values. - */ -JX9_PRIVATE sxi32 jx9CompileLiteral(jx9_gen_state *pGen,sxi32 iCompileFlag) -{ - SyToken *pToken = pGen->pIn; - jx9_value *pObj; - SyString *pStr; - sxu32 nIdx; - /* Extract token value */ - pStr = &pToken->sData; - /* Deal with the reserved literals [i.e: null, false, true, ...] first */ - if( pStr->nByte == sizeof("NULL") - 1 ){ - if( SyStrnicmp(pStr->zString, "null", sizeof("NULL")-1) == 0 ){ - /* NULL constant are always indexed at 0 */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, 0, 0, 0); - return SXRET_OK; - }else if( SyStrnicmp(pStr->zString, "true", sizeof("TRUE")-1) == 0 ){ - /* TRUE constant are always indexed at 1 */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, 1, 0, 0); - return SXRET_OK; - } - }else if (pStr->nByte == sizeof("FALSE") - 1 && - SyStrnicmp(pStr->zString, "false", sizeof("FALSE")-1) == 0 ){ - /* FALSE constant are always indexed at 2 */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, 2, 0, 0); - return SXRET_OK; - }else if(pStr->nByte == sizeof("__LINE__") - 1 && - SyMemcmp(pStr->zString, "__LINE__", sizeof("__LINE__")-1) == 0 ){ - /* TICKET 1433-004: __LINE__ constant must be resolved at compile time, not run time */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - SXUNUSED(iCompileFlag); /* cc warning */ - return GenStateOutOfMem(pGen); - } - jx9MemObjInitFromInt(pGen->pVm, pObj, pToken->nLine); - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - return SXRET_OK; - }else if( pStr->nByte == sizeof("__FUNCTION__") - 1 && - SyMemcmp(pStr->zString, "__FUNCTION__", sizeof("__FUNCTION__")-1) == 0 ){ - GenBlock *pBlock = pGen->pCurrent; - /* TICKET 1433-004: __FUNCTION__/__METHOD__ constants must be resolved at compile time, not run time */ - while( pBlock && (pBlock->iFlags & GEN_BLOCK_FUNC) == 0 ){ - /* Point to the upper block */ - pBlock = pBlock->pParent; - } - if( pBlock == 0 ){ - /* Called in the global scope, load NULL */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, 0, 0, 0); - }else{ - /* Extract the target function/method */ - jx9_vm_func *pFunc = (jx9_vm_func *)pBlock->pUserData; - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - return GenStateOutOfMem(pGen); - } - jx9MemObjInitFromString(pGen->pVm, pObj, &pFunc->sName); - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - } - return SXRET_OK; - } - /* Query literal table */ - if( SXRET_OK != GenStateFindLiteral(&(*pGen), &pToken->sData, &nIdx) ){ - jx9_value *pObj; - /* Unknown literal, install it in the literal table */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - return GenStateOutOfMem(pGen); - } - jx9MemObjInitFromString(pGen->pVm, pObj, &pToken->sData); - GenStateInstallLiteral(&(*pGen), pObj, nIdx); - } - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm,JX9_OP_LOADC,1,nIdx, 0, 0); - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Compile an array entry whether it is a key or a value. - */ -static sxi32 GenStateCompileJSONEntry( - jx9_gen_state *pGen, /* Code generator state */ - SyToken *pIn, /* Token stream */ - SyToken *pEnd, /* End of the token stream */ - sxi32 iFlags, /* Compilation flags */ - sxi32 (*xValidator)(jx9_gen_state *,jx9_expr_node *) /* Expression tree validator callback */ - ) -{ - SyToken *pTmpIn, *pTmpEnd; - sxi32 rc; - /* Swap token stream */ - SWAP_DELIMITER(pGen, pIn, pEnd); - /* Compile the expression*/ - rc = jx9CompileExpr(&(*pGen), iFlags, xValidator); - /* Restore token stream */ - RE_SWAP_DELIMITER(pGen); - return rc; -} -/* - * Compile a Jx9 JSON Array. - */ -JX9_PRIVATE sxi32 jx9CompileJsonArray(jx9_gen_state *pGen, sxi32 iCompileFlag) -{ - sxi32 nPair = 0; - SyToken *pCur; - sxi32 rc; - - pGen->pIn++; /* Jump the open square bracket '['*/ - pGen->pEnd--; - SXUNUSED(iCompileFlag); /* cc warning */ - for(;;){ - /* Jump leading commas */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_COMMA) ){ - pGen->pIn++; - } - pCur = pGen->pIn; - if( SXRET_OK != jx9GetNextExpr(pGen->pIn, pGen->pEnd, &pGen->pIn) ){ - /* No more entry to process */ - break; - } - /* Compile entry */ - rc = GenStateCompileJSONEntry(&(*pGen),pCur,pGen->pIn,EXPR_FLAG_RDONLY_LOAD/*Do not create the variable if inexistant*/,0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - nPair++; - } - /* Emit the load map instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOAD_MAP,nPair,0,0,0); - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Node validator for a given JSON key. - */ -static sxi32 GenStateJSONObjectKeyNodeValidator(jx9_gen_state *pGen,jx9_expr_node *pRoot) -{ - sxi32 rc = SXRET_OK; - if( pRoot->xCode != jx9CompileVariable && pRoot->xCode != jx9CompileString - && pRoot->xCode != jx9CompileSimpleString && pRoot->xCode != jx9CompileLiteral ){ - /* Unexpected expression */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pRoot->pStart? pRoot->pStart->nLine : 0, - "JSON Object: Unexpected expression, key must be of type string, literal or simple variable"); - if( rc != SXERR_ABORT ){ - rc = SXERR_INVALID; - } - } - return rc; -} -/* - * Compile a Jx9 JSON Object - */ -JX9_PRIVATE sxi32 jx9CompileJsonObject(jx9_gen_state *pGen, sxi32 iCompileFlag) -{ - SyToken *pKey, *pCur; - sxi32 nPair = 0; - sxi32 rc; - - pGen->pIn++; /* Jump the open querly braces '{'*/ - pGen->pEnd--; - SXUNUSED(iCompileFlag); /* cc warning */ - for(;;){ - /* Jump leading commas */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_COMMA) ){ - pGen->pIn++; - } - pCur = pGen->pIn; - if( SXRET_OK != jx9GetNextExpr(pGen->pIn, pGen->pEnd, &pGen->pIn) ){ - /* No more entry to process */ - break; - } - /* Compile the key */ - pKey = pCur; - while( pCur < pGen->pIn ){ - if( pCur->nType & JX9_TK_COLON /*':'*/ ){ - break; - } - pCur++; - } - rc = SXERR_EMPTY; - if( (pCur->nType & JX9_TK_COLON) == 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ABORT, pCur->nLine, "JSON Object: Missing colon string \":\""); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - return SXRET_OK; - } - - if( pCur < pGen->pIn ){ - if( &pCur[1] >= pGen->pIn ){ - /* Missing value */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pCur->nLine, "JSON Object: Missing entry value"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - return SXRET_OK; - } - /* Compile the expression holding the key */ - rc = GenStateCompileJSONEntry(&(*pGen), pKey, pCur, - EXPR_FLAG_RDONLY_LOAD /* Do not create the variable if inexistant */, - GenStateJSONObjectKeyNodeValidator /* Node validator callback */ - ); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - pCur++; /* Jump the double colon ':' */ - }else if( pKey == pCur ){ - /* Key is omitted, emit an error */ - jx9GenCompileError(&(*pGen),E_ERROR, pCur->nLine, "JSON Object: Missing entry key"); - pCur++; /* Jump the double colon ':' */ - }else{ - /* Reset back the cursor and point to the entry value */ - pCur = pKey; - } - /* Compile indice value */ - rc = GenStateCompileJSONEntry(&(*pGen), pCur, pGen->pIn, EXPR_FLAG_RDONLY_LOAD/*Do not create the variable if inexistant*/,0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - nPair++; - } - /* Emit the load map instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOAD_MAP, nPair * 2, 1, 0, 0); - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Compile a function [i.e: print, exit(), include(), ...] which is a langauge - * construct. - */ -JX9_PRIVATE sxi32 jx9CompileLangConstruct(jx9_gen_state *pGen,sxi32 iCompileFlag) -{ - SyString *pName; - sxu32 nKeyID; - sxi32 rc; - /* Name of the language construct [i.e: print, die...]*/ - pName = &pGen->pIn->sData; - nKeyID = (sxu32)SX_PTR_TO_INT(pGen->pIn->pUserData); - pGen->pIn++; /* Jump the language construct keyword */ - if( nKeyID == JX9_TKWRD_PRINT ){ - SyToken *pTmp, *pNext = 0; - /* Compile arguments one after one */ - pTmp = pGen->pEnd; - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, 1 /* Boolean true index */, 0, 0); - while( SXRET_OK == jx9GetNextExpr(pGen->pIn, pTmp, &pNext) ){ - if( pGen->pIn < pNext ){ - pGen->pEnd = pNext; - rc = jx9CompileExpr(&(*pGen), EXPR_FLAG_RDONLY_LOAD/* Do not create variable if inexistant */, 0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - if( rc != SXERR_EMPTY ){ - /* Ticket 1433-008: Optimization #1: Consume input directly - * without the overhead of a function call. - * This is a very powerful optimization that improve - * performance greatly. - */ - jx9VmEmitInstr(pGen->pVm,JX9_OP_CONSUME,1,0,0,0); - } - } - /* Jump trailing commas */ - while( pNext < pTmp && (pNext->nType & JX9_TK_COMMA) ){ - pNext++; - } - pGen->pIn = pNext; - } - /* Restore token stream */ - pGen->pEnd = pTmp; - }else{ - sxi32 nArg = 0; - sxu32 nIdx = 0; - rc = jx9CompileExpr(&(*pGen), EXPR_FLAG_RDONLY_LOAD/* Do not create variable if inexistant */, 0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - }else if(rc != SXERR_EMPTY ){ - nArg = 1; - } - if( SXRET_OK != GenStateFindLiteral(&(*pGen), pName, &nIdx) ){ - jx9_value *pObj; - /* Emit the call instruction */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - SXUNUSED(iCompileFlag); /* cc warning */ - return GenStateOutOfMem(pGen); - } - jx9MemObjInitFromString(pGen->pVm, pObj, pName); - /* Install in the literal table */ - GenStateInstallLiteral(&(*pGen), pObj, nIdx); - } - /* Emit the call instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - jx9VmEmitInstr(pGen->pVm, JX9_OP_CALL, nArg, 0, 0, 0); - } - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Compile a node holding a variable declaration. - * According to the J9X language reference - * Variables in JX9 are represented by a dollar sign followed by the name of the variable. - * The variable name is case-sensitive. - * Variable names follow the same rules as other labels in JX9. A valid variable name - * starts with a letter, underscore or any UTF-8 stream, followed by any number of letters - * numbers, or underscores. - * By default, variables are always assigned by value unless the target value is a JSON - * array or a JSON object which is passed by reference. - */ -JX9_PRIVATE sxi32 jx9CompileVariable(jx9_gen_state *pGen,sxi32 iCompileFlag) -{ - sxu32 nLine = pGen->pIn->nLine; - SyHashEntry *pEntry; - SyString *pName; - char *zName = 0; - sxi32 iP1; - void *p3; - sxi32 rc; - - pGen->pIn++; /* Jump the dollar sign '$' */ - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (JX9_TK_ID|JX9_TK_KEYWORD)) == 0 ){ - /* Invalid variable name */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Invalid variable name"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - return SXRET_OK; - } - /* Extract variable name */ - pName = &pGen->pIn->sData; - /* Advance the stream cursor */ - pGen->pIn++; - pEntry = SyHashGet(&pGen->hVar, (const void *)pName->zString, pName->nByte); - if( pEntry == 0 ){ - /* Duplicate name */ - zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); - if( zName == 0 ){ - return GenStateOutOfMem(pGen); - } - /* Install in the hashtable */ - SyHashInsert(&pGen->hVar, zName, pName->nByte, zName); - }else{ - /* Name already available */ - zName = (char *)pEntry->pUserData; - } - p3 = (void *)zName; - iP1 = 0; - if( iCompileFlag & EXPR_FLAG_RDONLY_LOAD ){ - if( (iCompileFlag & EXPR_FLAG_LOAD_IDX_STORE) == 0 ){ - /* Read-only load.In other words do not create the variable if inexistant */ - iP1 = 1; - } - } - /* Emit the load instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOAD, iP1, 0, p3, 0); - /* Node successfully compiled */ - return SXRET_OK; -} -/* Forward declaration */ -static sxi32 GenStateCompileFunc(jx9_gen_state *pGen,SyString *pName,sxi32 iFlags,jx9_vm_func **ppFunc); -/* - * Compile an annoynmous function or a closure. - * According to the JX9 language reference - * Anonymous functions, also known as closures, allow the creation of functions - * which have no specified name. They are most useful as the value of callback - * parameters, but they have many other uses. Closures can also be used as - * the values of variables; Assigning a closure to a variable uses the same - * syntax as any other assignment, including the trailing semicolon: - * Example Anonymous function variable assignment example - * $greet = function($name) - * { - * printf("Hello %s\r\n", $name); - * }; - * $greet('World'); - * $greet('JX9'); - * Note that the implementation of annoynmous function and closure under - * JX9 is completely different from the one used by the engine. - */ -JX9_PRIVATE sxi32 jx9CompileAnnonFunc(jx9_gen_state *pGen,sxi32 iCompileFlag) -{ - jx9_vm_func *pAnnonFunc; /* Annonymous function body */ - char zName[512]; /* Unique lambda name */ - static int iCnt = 1; /* There is no worry about thread-safety here, because only - * one thread is allowed to compile the script. - */ - jx9_value *pObj; - SyString sName; - sxu32 nIdx; - sxu32 nLen; - sxi32 rc; - - pGen->pIn++; /* Jump the 'function' keyword */ - if( pGen->pIn->nType & (JX9_TK_ID|JX9_TK_KEYWORD) ){ - pGen->pIn++; - } - /* Reserve a constant for the lambda */ - pObj = jx9VmReserveConstObj(pGen->pVm, &nIdx); - if( pObj == 0 ){ - GenStateOutOfMem(pGen); - SXUNUSED(iCompileFlag); /* cc warning */ - return SXERR_ABORT; - } - /* Generate a unique name */ - nLen = SyBufferFormat(zName, sizeof(zName), "[lambda_%d]", iCnt++); - /* Make sure the generated name is unique */ - while( SyHashGet(&pGen->pVm->hFunction, zName, nLen) != 0 && nLen < sizeof(zName) - 2 ){ - nLen = SyBufferFormat(zName, sizeof(zName), "[lambda_%d]", iCnt++); - } - SyStringInitFromBuf(&sName, zName, nLen); - jx9MemObjInitFromString(pGen->pVm, pObj, &sName); - /* Compile the lambda body */ - rc = GenStateCompileFunc(&(*pGen),&sName,0,&pAnnonFunc); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - /* Emit the load constant instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_LOADC, 0, nIdx, 0, 0); - /* Node successfully compiled */ - return SXRET_OK; -} -/* - * Compile the 'continue' statement. - * According to the JX9 language reference - * continue is used within looping structures to skip the rest of the current loop iteration - * and continue execution at the condition evaluation and then the beginning of the next - * iteration. - * Note: Note that in JX9 the switch statement is considered a looping structure for - * the purposes of continue. - * continue accepts an optional numeric argument which tells it how many levels - * of enclosing loops it should skip to the end of. - * Note: - * continue 0; and continue 1; is the same as running continue;. - */ -static sxi32 jx9CompileContinue(jx9_gen_state *pGen) -{ - GenBlock *pLoop; /* Target loop */ - sxi32 iLevel; /* How many nesting loop to skip */ - sxu32 nLine; - sxi32 rc; - nLine = pGen->pIn->nLine; - iLevel = 0; - /* Jump the 'continue' keyword */ - pGen->pIn++; - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_NUM) ){ - /* optional numeric argument which tells us how many levels - * of enclosing loops we should skip to the end of. - */ - iLevel = (sxi32)jx9TokenValueToInt64(&pGen->pIn->sData); - if( iLevel < 2 ){ - iLevel = 0; - } - pGen->pIn++; /* Jump the optional numeric argument */ - } - /* Point to the target loop */ - pLoop = GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, iLevel); - if( pLoop == 0 ){ - /* Illegal continue */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "A 'continue' statement may only be used within a loop or switch"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - }else{ - sxu32 nInstrIdx = 0; - /* Emit the unconditional jump to the beginning of the target loop */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JMP, 0, pLoop->nFirstInstr, 0, &nInstrIdx); - if( pLoop->bPostContinue == TRUE ){ - JumpFixup sJumpFix; - /* Post-continue */ - sJumpFix.nJumpType = JX9_OP_JMP; - sJumpFix.nInstrIdx = nInstrIdx; - SySetPut(&pLoop->aPostContFix, (const void *)&sJumpFix); - } - } - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - /* Not so fatal, emit a warning only */ - jx9GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, "Expected semi-colon ';' after 'continue' statement"); - } - /* Statement successfully compiled */ - return SXRET_OK; -} -/* - * Compile the 'break' statement. - * According to the JX9 language reference - * break ends execution of the current for, foreach, while, do-while or switch - * structure. - * break accepts an optional numeric argument which tells it how many nested - * enclosing structures are to be broken out of. - */ -static sxi32 jx9CompileBreak(jx9_gen_state *pGen) -{ - GenBlock *pLoop; /* Target loop */ - sxi32 iLevel; /* How many nesting loop to skip */ - sxu32 nLine; - sxi32 rc; - nLine = pGen->pIn->nLine; - iLevel = 0; - /* Jump the 'break' keyword */ - pGen->pIn++; - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_NUM) ){ - /* optional numeric argument which tells us how many levels - * of enclosing loops we should skip to the end of. - */ - iLevel = (sxi32)jx9TokenValueToInt64(&pGen->pIn->sData); - if( iLevel < 2 ){ - iLevel = 0; - } - pGen->pIn++; /* Jump the optional numeric argument */ - } - /* Extract the target loop */ - pLoop = GenStateFetchBlock(pGen->pCurrent, GEN_BLOCK_LOOP, iLevel); - if( pLoop == 0 ){ - /* Illegal break */ - rc = jx9GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "A 'break' statement may only be used within a loop or switch"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - }else{ - sxu32 nInstrIdx; - rc = jx9VmEmitInstr(pGen->pVm, JX9_OP_JMP, 0, 0, 0, &nInstrIdx); - if( rc == SXRET_OK ){ - /* Fix the jump later when the jump destination is resolved */ - GenStateNewJumpFixup(pLoop, JX9_OP_JMP, nInstrIdx); - } - } - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - /* Not so fatal, emit a warning only */ - jx9GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, "Expected semi-colon ';' after 'break' statement"); - } - /* Statement successfully compiled */ - return SXRET_OK; -} -/* Forward declaration */ -static sxi32 GenStateCompileChunk(jx9_gen_state *pGen,sxi32 iFlags); -/* - * Compile a JX9 block. - * A block is simply one or more JX9 statements and expressions to compile - * optionally delimited by braces {}. - * Return SXRET_OK on success. Any other return value indicates failure - * and this function takes care of generating the appropriate error - * message. - */ -static sxi32 jx9CompileBlock( - jx9_gen_state *pGen /* Code generator state */ - ) -{ - sxi32 rc; - if( pGen->pIn->nType & JX9_TK_OCB /* '{' */ ){ - sxu32 nLine = pGen->pIn->nLine; - rc = GenStateEnterBlock(&(*pGen), GEN_BLOCK_STD, jx9VmInstrLength(pGen->pVm), 0, 0); - if( rc != SXRET_OK ){ - return SXERR_ABORT; - } - pGen->pIn++; - /* Compile until we hit the closing braces '}' */ - for(;;){ - if( pGen->pIn >= pGen->pEnd ){ - /* No more token to process. Missing closing braces */ - jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Missing closing braces '}'"); - break; - } - if( pGen->pIn->nType & JX9_TK_CCB/*'}'*/ ){ - /* Closing braces found, break immediately*/ - pGen->pIn++; - break; - } - /* Compile a single statement */ - rc = GenStateCompileChunk(&(*pGen),JX9_COMPILE_SINGLE_STMT); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - } - GenStateLeaveBlock(&(*pGen), 0); - }else{ - /* Compile a single statement */ - rc = GenStateCompileChunk(&(*pGen),JX9_COMPILE_SINGLE_STMT); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - } - /* Jump trailing semi-colons ';' */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) ){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Compile the gentle 'while' statement. - * According to the JX9 language reference - * while loops are the simplest type of loop in JX9.They behave just like their C counterparts. - * The basic form of a while statement is: - * while (expr) - * statement - * The meaning of a while statement is simple. It tells JX9 to execute the nested statement(s) - * repeatedly, as long as the while expression evaluates to TRUE. The value of the expression - * is checked each time at the beginning of the loop, so even if this value changes during - * the execution of the nested statement(s), execution will not stop until the end of the iteration - * (each time JX9 runs the statements in the loop is one iteration). Sometimes, if the while - * expression evaluates to FALSE from the very beginning, the nested statement(s) won't even be run once. - * Like with the if statement, you can group multiple statements within the same while loop by surrounding - * a group of statements with curly braces, or by using the alternate syntax: - * while (expr): - * statement - * endwhile; - */ -static sxi32 jx9CompileWhile(jx9_gen_state *pGen) -{ - GenBlock *pWhileBlock = 0; - SyToken *pTmp, *pEnd = 0; - sxu32 nFalseJump; - sxu32 nLine; - sxi32 rc; - nLine = pGen->pIn->nLine; - /* Jump the 'while' keyword */ - pGen->pIn++; - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_LPAREN) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Expected '(' after 'while' keyword"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Jump the left parenthesis '(' */ - pGen->pIn++; - /* Create the loop block */ - rc = GenStateEnterBlock(&(*pGen), GEN_BLOCK_LOOP, jx9VmInstrLength(pGen->pVm), 0, &pWhileBlock); - if( rc != SXRET_OK ){ - return SXERR_ABORT; - } - /* Delimit the condition */ - jx9DelimitNestedTokens(pGen->pIn, pGen->pEnd, JX9_TK_LPAREN /* '(' */, JX9_TK_RPAREN /* ')' */, &pEnd); - if( pGen->pIn == pEnd || pEnd >= pGen->pEnd ){ - /* Empty expression */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Expected expression after 'while' keyword"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - } - /* Swap token streams */ - pTmp = pGen->pEnd; - pGen->pEnd = pEnd; - /* Compile the expression */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - /* Expression handler request an operation abort [i.e: Out-of-memory] */ - return SXERR_ABORT; - } - /* Update token stream */ - while(pGen->pIn < pEnd ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Unexpected token '%z'", &pGen->pIn->sData); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - pGen->pIn++; - } - /* Synchronize pointers */ - pGen->pIn = &pEnd[1]; - pGen->pEnd = pTmp; - /* Emit the false jump */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JZ, 0, 0, 0, &nFalseJump); - /* Save the instruction index so we can fix it later when the jump destination is resolved */ - GenStateNewJumpFixup(pWhileBlock, JX9_OP_JZ, nFalseJump); - /* Compile the loop body */ - rc = jx9CompileBlock(&(*pGen)); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - /* Emit the unconditional jump to the start of the loop */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JMP, 0, pWhileBlock->nFirstInstr, 0, 0); - /* Fix all jumps now the destination is resolved */ - GenStateFixJumps(pWhileBlock, -1, jx9VmInstrLength(pGen->pVm)); - /* Release the loop block */ - GenStateLeaveBlock(pGen, 0); - /* Statement successfully compiled */ - return SXRET_OK; -Synchronize: - /* Synchronize with the first semi-colon ';' so we can avoid - * compiling this erroneous block. - */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (JX9_TK_SEMI|JX9_TK_OCB)) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Compile the complex and powerful 'for' statement. - * According to the JX9 language reference - * for loops are the most complex loops in JX9. They behave like their C counterparts. - * The syntax of a for loop is: - * for (expr1; expr2; expr3) - * statement - * The first expression (expr1) is evaluated (executed) once unconditionally at - * the beginning of the loop. - * In the beginning of each iteration, expr2 is evaluated. If it evaluates to - * TRUE, the loop continues and the nested statement(s) are executed. If it evaluates - * to FALSE, the execution of the loop ends. - * At the end of each iteration, expr3 is evaluated (executed). - * Each of the expressions can be empty or contain multiple expressions separated by commas. - * In expr2, all expressions separated by a comma are evaluated but the result is taken - * from the last part. expr2 being empty means the loop should be run indefinitely - * (JX9 implicitly considers it as TRUE, like C). This may not be as useless as you might - * think, since often you'd want to end the loop using a conditional break statement instead - * of using the for truth expression. - */ -static sxi32 jx9CompileFor(jx9_gen_state *pGen) -{ - SyToken *pTmp, *pPostStart, *pEnd = 0; - GenBlock *pForBlock = 0; - sxu32 nFalseJump; - sxu32 nLine; - sxi32 rc; - nLine = pGen->pIn->nLine; - /* Jump the 'for' keyword */ - pGen->pIn++; - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_LPAREN) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Expected '(' after 'for' keyword"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - return SXRET_OK; - } - /* Jump the left parenthesis '(' */ - pGen->pIn++; - /* Delimit the init-expr;condition;post-expr */ - jx9DelimitNestedTokens(pGen->pIn, pGen->pEnd, JX9_TK_LPAREN /* '(' */, JX9_TK_RPAREN /* ')' */, &pEnd); - if( pGen->pIn == pEnd || pEnd >= pGen->pEnd ){ - /* Empty expression */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "for: Invalid expression"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - /* Synchronize */ - pGen->pIn = pEnd; - if( pGen->pIn < pGen->pEnd ){ - pGen->pIn++; - } - return SXRET_OK; - } - /* Swap token streams */ - pTmp = pGen->pEnd; - pGen->pEnd = pEnd; - /* Compile initialization expressions if available */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - /* Pop operand lvalues */ - if( rc == SXERR_ABORT ){ - /* Expression handler request an operation abort [i.e: Out-of-memory] */ - return SXERR_ABORT; - }else if( rc != SXERR_EMPTY ){ - jx9VmEmitInstr(pGen->pVm, JX9_OP_POP, 1, 0, 0, 0); - } - if( (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "for: Expected ';' after initialization expressions"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - return SXRET_OK; - } - /* Jump the trailing ';' */ - pGen->pIn++; - /* Create the loop block */ - rc = GenStateEnterBlock(&(*pGen), GEN_BLOCK_LOOP, jx9VmInstrLength(pGen->pVm), 0, &pForBlock); - if( rc != SXRET_OK ){ - return SXERR_ABORT; - } - /* Deffer continue jumps */ - pForBlock->bPostContinue = TRUE; - /* Compile the condition */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - /* Expression handler request an operation abort [i.e: Out-of-memory] */ - return SXERR_ABORT; - }else if( rc != SXERR_EMPTY ){ - /* Emit the false jump */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JZ, 0, 0, 0, &nFalseJump); - /* Save the instruction index so we can fix it later when the jump destination is resolved */ - GenStateNewJumpFixup(pForBlock, JX9_OP_JZ, nFalseJump); - } - if( (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "for: Expected ';' after conditionals expressions"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - return SXRET_OK; - } - /* Jump the trailing ';' */ - pGen->pIn++; - /* Save the post condition stream */ - pPostStart = pGen->pIn; - /* Compile the loop body */ - pGen->pIn = &pEnd[1]; /* Jump the trailing parenthesis ')' */ - pGen->pEnd = pTmp; - rc = jx9CompileBlock(&(*pGen)); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - /* Fix post-continue jumps */ - if( SySetUsed(&pForBlock->aPostContFix) > 0 ){ - JumpFixup *aPost; - VmInstr *pInstr; - sxu32 nJumpDest; - sxu32 n; - aPost = (JumpFixup *)SySetBasePtr(&pForBlock->aPostContFix); - nJumpDest = jx9VmInstrLength(pGen->pVm); - for( n = 0 ; n < SySetUsed(&pForBlock->aPostContFix) ; ++n ){ - pInstr = jx9VmGetInstr(pGen->pVm, aPost[n].nInstrIdx); - if( pInstr ){ - /* Fix jump */ - pInstr->iP2 = nJumpDest; - } - } - } - /* compile the post-expressions if available */ - while( pPostStart < pEnd && (pPostStart->nType & JX9_TK_SEMI) ){ - pPostStart++; - } - if( pPostStart < pEnd ){ - SyToken *pTmpIn, *pTmpEnd; - SWAP_DELIMITER(pGen, pPostStart, pEnd); - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( pGen->pIn < pGen->pEnd ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "for: Expected ')' after post-expressions"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - return SXRET_OK; - } - RE_SWAP_DELIMITER(pGen); - if( rc == SXERR_ABORT ){ - /* Expression handler request an operation abort [i.e: Out-of-memory] */ - return SXERR_ABORT; - }else if( rc != SXERR_EMPTY){ - /* Pop operand lvalue */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_POP, 1, 0, 0, 0); - } - } - /* Emit the unconditional jump to the start of the loop */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JMP, 0, pForBlock->nFirstInstr, 0, 0); - /* Fix all jumps now the destination is resolved */ - GenStateFixJumps(pForBlock, -1, jx9VmInstrLength(pGen->pVm)); - /* Release the loop block */ - GenStateLeaveBlock(pGen, 0); - /* Statement successfully compiled */ - return SXRET_OK; -} -/* Expression tree validator callback used by the 'foreach' statement. - * Note that only variable expression [i.e: $x; ${'My'.'Var'}; ${$a['key]};...] - * are allowed. - */ -static sxi32 GenStateForEachNodeValidator(jx9_gen_state *pGen,jx9_expr_node *pRoot) -{ - sxi32 rc = SXRET_OK; /* Assume a valid expression tree */ - if( pRoot->xCode != jx9CompileVariable ){ - /* Unexpected expression */ - rc = jx9GenCompileError(&(*pGen), - E_ERROR, - pRoot->pStart? pRoot->pStart->nLine : 0, - "foreach: Expecting a variable name" - ); - if( rc != SXERR_ABORT ){ - rc = SXERR_INVALID; - } - } - return rc; -} -/* - * Compile the 'foreach' statement. - * According to the JX9 language reference - * The foreach construct simply gives an easy way to iterate over arrays. foreach works - * only on arrays (and objects), and will issue an error when you try to use it on a variable - * with a different data type or an uninitialized variable. There are two syntaxes; the second - * is a minor but useful extension of the first: - * foreach (json_array_json_object as $value) - * statement - * foreach (json_array_json_objec as $key,$value) - * statement - * The first form loops over the array given by array_expression. On each loop, the value - * of the current element is assigned to $value and the internal array pointer is advanced - * by one (so on the next loop, you'll be looking at the next element). - * The second form does the same thing, except that the current element's key will be assigned - * to the variable $key on each loop. - * Note: - * When foreach first starts executing, the internal array pointer is automatically reset to the - * first element of the array. This means that you do not need to call reset() before a foreach loop. - */ -static sxi32 jx9CompileForeach(jx9_gen_state *pGen) -{ - SyToken *pCur, *pTmp, *pEnd = 0; - GenBlock *pForeachBlock = 0; - jx9_foreach_info *pInfo; - sxu32 nFalseJump; - VmInstr *pInstr; - sxu32 nLine; - sxi32 rc; - nLine = pGen->pIn->nLine; - /* Jump the 'foreach' keyword */ - pGen->pIn++; - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_LPAREN) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "foreach: Expected '('"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Jump the left parenthesis '(' */ - pGen->pIn++; - /* Create the loop block */ - rc = GenStateEnterBlock(&(*pGen), GEN_BLOCK_LOOP, jx9VmInstrLength(pGen->pVm), 0, &pForeachBlock); - if( rc != SXRET_OK ){ - return SXERR_ABORT; - } - /* Delimit the expression */ - jx9DelimitNestedTokens(pGen->pIn, pGen->pEnd, JX9_TK_LPAREN /* '(' */, JX9_TK_RPAREN /* ')' */, &pEnd); - if( pGen->pIn == pEnd || pEnd >= pGen->pEnd ){ - /* Empty expression */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "foreach: Missing expression"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - /* Synchronize */ - pGen->pIn = pEnd; - if( pGen->pIn < pGen->pEnd ){ - pGen->pIn++; - } - return SXRET_OK; - } - /* Compile the array expression */ - pCur = pGen->pIn; - while( pCur < pEnd ){ - if( pCur->nType & JX9_TK_KEYWORD ){ - sxi32 nKeywrd = SX_PTR_TO_INT(pCur->pUserData); - if( nKeywrd == JX9_TKWRD_AS ){ - /* Break with the first 'as' found */ - break; - } - } - /* Advance the stream cursor */ - pCur++; - } - if( pCur <= pGen->pIn ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, - "foreach: Missing array/object expression"); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Swap token streams */ - pTmp = pGen->pEnd; - pGen->pEnd = pCur; - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - /* Expression handler request an operation abort [i.e: Out-of-memory] */ - return SXERR_ABORT; - } - /* Update token stream */ - while(pGen->pIn < pCur ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Unexpected token '%z'", &pGen->pIn->sData); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - pGen->pIn++; - } - pCur++; /* Jump the 'as' keyword */ - pGen->pIn = pCur; - if( pGen->pIn >= pEnd ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $key => $value pair"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - } - /* Create the foreach context */ - pInfo = (jx9_foreach_info *)SyMemBackendAlloc(&pGen->pVm->sAllocator, sizeof(jx9_foreach_info)); - if( pInfo == 0 ){ - jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Fatal, JX9 engine is running out-of-memory"); - return SXERR_ABORT; - } - /* Zero the structure */ - SyZero(pInfo, sizeof(jx9_foreach_info)); - /* Initialize structure fields */ - SySetInit(&pInfo->aStep, &pGen->pVm->sAllocator, sizeof(jx9_foreach_step *)); - /* Check if we have a key field */ - while( pCur < pEnd && (pCur->nType & JX9_TK_COMMA) == 0 ){ - pCur++; - } - if( pCur < pEnd ){ - /* Compile the expression holding the key name */ - if( pGen->pIn >= pCur ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $key"); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - }else{ - pGen->pEnd = pCur; - rc = jx9CompileExpr(&(*pGen), 0, GenStateForEachNodeValidator); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - pInstr = jx9VmPopInstr(pGen->pVm); - if( pInstr->p3 ){ - /* Record key name */ - SyStringInitFromBuf(&pInfo->sKey, pInstr->p3, SyStrlen((const char *)pInstr->p3)); - } - pInfo->iFlags |= JX9_4EACH_STEP_KEY; - } - pGen->pIn = &pCur[1]; /* Jump the arrow */ - } - pGen->pEnd = pEnd; - if( pGen->pIn >= pEnd ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "foreach: Missing $value"); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Compile the expression holding the value name */ - rc = jx9CompileExpr(&(*pGen), 0, GenStateForEachNodeValidator); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - pInstr = jx9VmPopInstr(pGen->pVm); - if( pInstr->p3 ){ - /* Record value name */ - SyStringInitFromBuf(&pInfo->sValue, pInstr->p3, SyStrlen((const char *)pInstr->p3)); - } - /* Emit the 'FOREACH_INIT' instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_FOREACH_INIT, 0, 0, pInfo, &nFalseJump); - /* Save the instruction index so we can fix it later when the jump destination is resolved */ - GenStateNewJumpFixup(pForeachBlock, JX9_OP_FOREACH_INIT, nFalseJump); - /* Record the first instruction to execute */ - pForeachBlock->nFirstInstr = jx9VmInstrLength(pGen->pVm); - /* Emit the FOREACH_STEP instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_FOREACH_STEP, 0, 0, pInfo, &nFalseJump); - /* Save the instruction index so we can fix it later when the jump destination is resolved */ - GenStateNewJumpFixup(pForeachBlock, JX9_OP_FOREACH_STEP, nFalseJump); - /* Compile the loop body */ - pGen->pIn = &pEnd[1]; - pGen->pEnd = pTmp; - rc = jx9CompileBlock(&(*pGen)); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - /* Emit the unconditional jump to the start of the loop */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JMP, 0, pForeachBlock->nFirstInstr, 0, 0); - /* Fix all jumps now the destination is resolved */ - GenStateFixJumps(pForeachBlock, -1,jx9VmInstrLength(pGen->pVm)); - /* Release the loop block */ - GenStateLeaveBlock(pGen, 0); - /* Statement successfully compiled */ - return SXRET_OK; -Synchronize: - /* Synchronize with the first semi-colon ';' so we can avoid - * compiling this erroneous block. - */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (JX9_TK_SEMI|JX9_TK_OCB)) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Compile the infamous if/elseif/else if/else statements. - * According to the JX9 language reference - * The if construct is one of the most important features of many languages JX9 included. - * It allows for conditional execution of code fragments. JX9 features an if structure - * that is similar to that of C: - * if (expr) - * statement - * else construct: - * Often you'd want to execute a statement if a certain condition is met, and a different - * statement if the condition is not met. This is what else is for. else extends an if statement - * to execute a statement in case the expression in the if statement evaluates to FALSE. - * For example, the following code would display a is greater than b if $a is greater than - * $b, and a is NOT greater than b otherwise. - * The else statement is only executed if the if expression evaluated to FALSE, and if there - * were any elseif expressions - only if they evaluated to FALSE as well - * elseif - * elseif, as its name suggests, is a combination of if and else. Like else, it extends - * an if statement to execute a different statement in case the original if expression evaluates - * to FALSE. However, unlike else, it will execute that alternative expression only if the elseif - * conditional expression evaluates to TRUE. For example, the following code would display a is bigger - * than b, a equal to b or a is smaller than b: - * if ($a > $b) { - * print "a is bigger than b"; - * } elseif ($a == $b) { - * print "a is equal to b"; - * } else { - * print "a is smaller than b"; - * } - */ -static sxi32 jx9CompileIf(jx9_gen_state *pGen) -{ - SyToken *pToken, *pTmp, *pEnd = 0; - GenBlock *pCondBlock = 0; - sxu32 nJumpIdx; - sxu32 nKeyID; - sxi32 rc; - /* Jump the 'if' keyword */ - pGen->pIn++; - pToken = pGen->pIn; - /* Create the conditional block */ - rc = GenStateEnterBlock(&(*pGen), GEN_BLOCK_COND, jx9VmInstrLength(pGen->pVm), 0, &pCondBlock); - if( rc != SXRET_OK ){ - return SXERR_ABORT; - } - /* Process as many [if/else if/elseif/else] blocks as we can */ - for(;;){ - if( pToken >= pGen->pEnd || (pToken->nType & JX9_TK_LPAREN) == 0 ){ - /* Syntax error */ - if( pToken >= pGen->pEnd ){ - pToken--; - } - rc = jx9GenCompileError(pGen, E_ERROR, pToken->nLine, "if/else/elseif: Missing '('"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Jump the left parenthesis '(' */ - pToken++; - /* Delimit the condition */ - jx9DelimitNestedTokens(pToken, pGen->pEnd, JX9_TK_LPAREN /* '(' */, JX9_TK_RPAREN /* ')' */, &pEnd); - if( pToken >= pEnd || (pEnd->nType & JX9_TK_RPAREN) == 0 ){ - /* Syntax error */ - if( pToken >= pGen->pEnd ){ - pToken--; - } - rc = jx9GenCompileError(pGen, E_ERROR, pToken->nLine, "if/else/elseif: Missing ')'"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Swap token streams */ - SWAP_TOKEN_STREAM(pGen, pToken, pEnd); - /* Compile the condition */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - /* Update token stream */ - while(pGen->pIn < pEnd ){ - jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Unexpected token '%z'", &pGen->pIn->sData); - pGen->pIn++; - } - pGen->pIn = &pEnd[1]; - pGen->pEnd = pTmp; - if( rc == SXERR_ABORT ){ - /* Expression handler request an operation abort [i.e: Out-of-memory] */ - return SXERR_ABORT; - } - /* Emit the false jump */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JZ, 0, 0, 0, &nJumpIdx); - /* Save the instruction index so we can fix it later when the jump destination is resolved */ - GenStateNewJumpFixup(pCondBlock, JX9_OP_JZ, nJumpIdx); - /* Compile the body */ - rc = jx9CompileBlock(&(*pGen)); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_KEYWORD) == 0 ){ - break; - } - /* Ensure that the keyword ID is 'else if' or 'else' */ - nKeyID = (sxu32)SX_PTR_TO_INT(pGen->pIn->pUserData); - if( (nKeyID & (JX9_TKWRD_ELSE|JX9_TKWRD_ELIF)) == 0 ){ - break; - } - /* Emit the unconditional jump */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JMP, 0, 0, 0, &nJumpIdx); - /* Save the instruction index so we can fix it later when the jump destination is resolved */ - GenStateNewJumpFixup(pCondBlock, JX9_OP_JMP, nJumpIdx); - if( nKeyID & JX9_TKWRD_ELSE ){ - pToken = &pGen->pIn[1]; - if( pToken >= pGen->pEnd || (pToken->nType & JX9_TK_KEYWORD) == 0 || - SX_PTR_TO_INT(pToken->pUserData) != JX9_TKWRD_IF ){ - break; - } - pGen->pIn++; /* Jump the 'else' keyword */ - } - pGen->pIn++; /* Jump the 'elseif/if' keyword */ - /* Synchronize cursors */ - pToken = pGen->pIn; - /* Fix the false jump */ - GenStateFixJumps(pCondBlock, JX9_OP_JZ, jx9VmInstrLength(pGen->pVm)); - } /* For(;;) */ - /* Fix the false jump */ - GenStateFixJumps(pCondBlock, JX9_OP_JZ, jx9VmInstrLength(pGen->pVm)); - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_KEYWORD) && - (SX_PTR_TO_INT(pGen->pIn->pUserData) & JX9_TKWRD_ELSE) ){ - /* Compile the else block */ - pGen->pIn++; - rc = jx9CompileBlock(&(*pGen)); - if( rc == SXERR_ABORT ){ - - return SXERR_ABORT; - } - } - nJumpIdx = jx9VmInstrLength(pGen->pVm); - /* Fix all unconditional jumps now the destination is resolved */ - GenStateFixJumps(pCondBlock, JX9_OP_JMP, nJumpIdx); - /* Release the conditional block */ - GenStateLeaveBlock(pGen, 0); - /* Statement successfully compiled */ - return SXRET_OK; -Synchronize: - /* Synchronize with the first semi-colon ';' so we can avoid compiling this erroneous block. - */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (JX9_TK_SEMI|JX9_TK_OCB)) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Compile the return statement. - * According to the JX9 language reference - * If called from within a function, the return() statement immediately ends execution - * of the current function, and returns its argument as the value of the function call. - * return() will also end the execution of an eval() statement or script file. - * If called from the global scope, then execution of the current script file is ended. - * If the current script file was include()ed or require()ed, then control is passed back - * to the calling file. Furthermore, if the current script file was include()ed, then the value - * given to return() will be returned as the value of the include() call. If return() is called - * from within the main script file, then script execution end. - * Note that since return() is a language construct and not a function, the parentheses - * surrounding its arguments are not required. It is common to leave them out, and you actually - * should do so as JX9 has less work to do in this case. - * Note: If no parameter is supplied, then the parentheses must be omitted and JX9 is returning NULL instead.. - */ -static sxi32 jx9CompileReturn(jx9_gen_state *pGen) -{ - sxi32 nRet = 0; /* TRUE if there is a return value */ - sxi32 rc; - /* Jump the 'return' keyword */ - pGen->pIn++; - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - /* Compile the expression */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - }else if(rc != SXERR_EMPTY ){ - nRet = 1; - } - } - /* Emit the done instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_DONE, nRet, 0, 0, 0); - return SXRET_OK; -} -/* - * Compile the die/exit language construct. - * The role of these constructs is to terminate execution of the script. - * Shutdown functions will always be executed even if exit() is called. - */ -static sxi32 jx9CompileHalt(jx9_gen_state *pGen) -{ - sxi32 nExpr = 0; - sxi32 rc; - /* Jump the die/exit keyword */ - pGen->pIn++; - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - /* Compile the expression */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - }else if(rc != SXERR_EMPTY ){ - nExpr = 1; - } - } - /* Emit the HALT instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_HALT, nExpr, 0, 0, 0); - return SXRET_OK; -} -/* - * Compile the static statement. - * According to the JX9 language reference - * Another important feature of variable scoping is the static variable. - * A static variable exists only in a local function scope, but it does not lose its value - * when program execution leaves this scope. - * Static variables also provide one way to deal with recursive functions. - */ -static sxi32 jx9CompileStatic(jx9_gen_state *pGen) -{ - jx9_vm_func_static_var sStatic; /* Structure describing the static variable */ - jx9_vm_func *pFunc; /* Enclosing function */ - GenBlock *pBlock; - SyString *pName; - char *zDup; - sxu32 nLine; - sxi32 rc; - /* Jump the static keyword */ - nLine = pGen->pIn->nLine; - pGen->pIn++; - /* Extract the enclosing function if any */ - pBlock = pGen->pCurrent; - while( pBlock ){ - if( pBlock->iFlags & GEN_BLOCK_FUNC){ - break; - } - /* Point to the upper block */ - pBlock = pBlock->pParent; - } - if( pBlock == 0 ){ - /* Static statement, called outside of a function body, treat it as a simple variable. */ - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_DOLLAR) == 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Expected variable after 'static' keyword"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Compile the expression holding the variable */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - }else if( rc != SXERR_EMPTY ){ - /* Emit the POP instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_POP, 1, 0, 0, 0); - } - return SXRET_OK; - } - pFunc = (jx9_vm_func *)pBlock->pUserData; - /* Make sure we are dealing with a valid statement */ - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_DOLLAR) == 0 || &pGen->pIn[1] >= pGen->pEnd || - (pGen->pIn[1].nType & (JX9_TK_ID|JX9_TK_KEYWORD)) == 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Expected variable after 'static' keyword"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - goto Synchronize; - } - pGen->pIn++; - /* Extract variable name */ - pName = &pGen->pIn->sData; - pGen->pIn++; /* Jump the var name */ - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (JX9_TK_SEMI/*';'*/|JX9_TK_EQUAL/*'='*/)) == 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "static: Unexpected token '%z'", &pGen->pIn->sData); - goto Synchronize; - } - /* Initialize the structure describing the static variable */ - SySetInit(&sStatic.aByteCode, &pGen->pVm->sAllocator, sizeof(VmInstr)); - sStatic.nIdx = SXU32_HIGH; /* Not yet created */ - /* Duplicate variable name */ - zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); - if( zDup == 0 ){ - jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Fatal, JX9 engine is running out of memory"); - return SXERR_ABORT; - } - SyStringInitFromBuf(&sStatic.sName, zDup, pName->nByte); - /* Check if we have an expression to compile */ - if( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_EQUAL) ){ - SySet *pInstrContainer; - pGen->pIn++; /* Jump the equal '=' sign */ - /* Swap bytecode container */ - pInstrContainer = jx9VmGetByteCodeContainer(pGen->pVm); - jx9VmSetByteCodeContainer(pGen->pVm, &sStatic.aByteCode); - /* Compile the expression */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - /* Emit the done instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); - /* Restore default bytecode container */ - jx9VmSetByteCodeContainer(pGen->pVm, pInstrContainer); - } - /* Finally save the compiled static variable in the appropriate container */ - SySetPut(&pFunc->aStatic, (const void *)&sStatic); - return SXRET_OK; -Synchronize: - /* Synchronize with the first semi-colon ';', so we can avoid compiling this erroneous - * statement. - */ - while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Compile the 'const' statement. - * According to the JX9 language reference - * A constant is an identifier (name) for a simple value. As the name suggests, that value - * cannot change during the execution of the script (except for magic constants, which aren't actually constants). - * A constant is case-sensitive by default. By convention, constant identifiers are always uppercase. - * The name of a constant follows the same rules as any label in JX9. A valid constant name starts - * with a letter or underscore, followed by any number of letters, numbers, or underscores. - * As a regular expression it would be expressed thusly: [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]* - * Syntax - * You can define a constant by using the define()-function or by using the const keyword outside - * a object definition. Once a constant is defined, it can never be changed or undefined. - * You can get the value of a constant by simply specifying its name. Unlike with variables - * you should not prepend a constant with a $. You can also use the function constant() to read - * a constant's value if you wish to obtain the constant's name dynamically. Use get_defined_constants() - * to get a list of all defined constants. - */ -static sxi32 jx9CompileConstant(jx9_gen_state *pGen) -{ - SySet *pConsCode, *pInstrContainer; - sxu32 nLine = pGen->pIn->nLine; - SyString *pName; - sxi32 rc; - pGen->pIn++; /* Jump the 'const' keyword */ - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (JX9_TK_SSTR|JX9_TK_DSTR|JX9_TK_ID|JX9_TK_KEYWORD)) == 0 ){ - /* Invalid constant name */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "const: Invalid constant name"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Peek constant name */ - pName = &pGen->pIn->sData; - /* Make sure the constant name isn't reserved */ - if( GenStateIsReservedID(pName) ){ - /* Reserved constant */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "const: Cannot redeclare a reserved constant '%z'", pName); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - pGen->pIn++; - if(pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_EQUAL /* '=' */) == 0 ){ - /* Invalid statement*/ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "const: Expected '=' after constant name"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - pGen->pIn++; /*Jump the equal sign */ - /* Allocate a new constant value container */ - pConsCode = (SySet *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(SySet)); - if( pConsCode == 0 ){ - return GenStateOutOfMem(pGen); - } - SySetInit(pConsCode, &pGen->pVm->sAllocator, sizeof(VmInstr)); - /* Swap bytecode container */ - pInstrContainer = jx9VmGetByteCodeContainer(pGen->pVm); - jx9VmSetByteCodeContainer(pGen->pVm, pConsCode); - /* Compile constant value */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - /* Emit the done instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); - jx9VmSetByteCodeContainer(pGen->pVm, pInstrContainer); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - SySetSetUserData(pConsCode, pGen->pVm); - /* Register the constant */ - rc = jx9VmRegisterConstant(pGen->pVm, pName, jx9VmExpandConstantValue, pConsCode); - if( rc != SXRET_OK ){ - SySetRelease(pConsCode); - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pConsCode); - } - return SXRET_OK; -Synchronize: - /* Synchronize with the next-semi-colon and avoid compiling this erroneous statement */ - while(pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Compile the uplink construct. - * According to the JX9 language reference - * In JX9 global variables must be declared uplink inside a function if they are going - * to be used in that function. - * Example #1 Using global - * $a = 1; - * $b = 2; - * function Sum() - * { - * uplink $a, $b; - * $b = $a + $b; - * } - * Sum(); - * print $b; - * ?> - * The above script will output 3. By declaring $a and $b global within the function - * all references to either variable will refer to the global version. There is no limit - * to the number of global variables that can be manipulated by a function. - */ -static sxi32 jx9CompileUplink(jx9_gen_state *pGen) -{ - SyToken *pTmp, *pNext = 0; - sxi32 nExpr; - sxi32 rc; - /* Jump the 'uplink' keyword */ - pGen->pIn++; - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_SEMI) ){ - /* Nothing to process */ - return SXRET_OK; - } - pTmp = pGen->pEnd; - nExpr = 0; - while( SXRET_OK == jx9GetNextExpr(pGen->pIn, pTmp, &pNext) ){ - if( pGen->pIn < pNext ){ - pGen->pEnd = pNext; - if( (pGen->pIn->nType & JX9_TK_DOLLAR) == 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "uplink: Expected variable name"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - }else{ - pGen->pIn++; - if( pGen->pIn >= pGen->pEnd ){ - /* Emit a warning */ - jx9GenCompileError(&(*pGen), E_WARNING, pGen->pIn[-1].nLine, "uplink: Empty variable name"); - }else{ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - }else if(rc != SXERR_EMPTY ){ - nExpr++; - } - } - } - } - /* Next expression in the stream */ - pGen->pIn = pNext; - /* Jump trailing commas */ - while( pGen->pIn < pTmp && (pGen->pIn->nType & JX9_TK_COMMA) ){ - pGen->pIn++; - } - } - /* Restore token stream */ - pGen->pEnd = pTmp; - if( nExpr > 0 ){ - /* Emit the uplink instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_UPLINK, nExpr, 0, 0, 0); - } - return SXRET_OK; -} -/* - * Compile a switch block. - * (See block-comment below for more information) - */ -static sxi32 GenStateCompileSwitchBlock(jx9_gen_state *pGen,sxu32 *pBlockStart) -{ - sxi32 rc = SXRET_OK; - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (JX9_TK_SEMI/*';'*/|JX9_TK_COLON/*':'*/)) == 0 ){ - /* Unexpected token */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Unexpected token '%z'", &pGen->pIn->sData); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - pGen->pIn++; - } - pGen->pIn++; - /* First instruction to execute in this block. */ - *pBlockStart = jx9VmInstrLength(pGen->pVm); - /* Compile the block until we hit a case/default/endswitch keyword - * or the '}' token */ - for(;;){ - if( pGen->pIn >= pGen->pEnd ){ - /* No more input to process */ - break; - } - rc = SXRET_OK; - if( (pGen->pIn->nType & JX9_TK_KEYWORD) == 0 ){ - if( pGen->pIn->nType & JX9_TK_CCB /*'}' */ ){ - rc = SXERR_EOF; - break; - } - }else{ - sxi32 nKwrd; - /* Extract the keyword */ - nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - if( nKwrd == JX9_TKWRD_CASE || nKwrd == JX9_TKWRD_DEFAULT ){ - break; - } - } - /* Compile block */ - rc = jx9CompileBlock(&(*pGen)); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - } - return rc; -} -/* - * Compile a case eXpression. - * (See block-comment below for more information) - */ -static sxi32 GenStateCompileCaseExpr(jx9_gen_state *pGen, jx9_case_expr *pExpr) -{ - SySet *pInstrContainer; - SyToken *pEnd, *pTmp; - sxi32 iNest = 0; - sxi32 rc; - /* Delimit the expression */ - pEnd = pGen->pIn; - while( pEnd < pGen->pEnd ){ - if( pEnd->nType & JX9_TK_LPAREN /*(*/ ){ - /* Increment nesting level */ - iNest++; - }else if( pEnd->nType & JX9_TK_RPAREN /*)*/ ){ - /* Decrement nesting level */ - iNest--; - }else if( pEnd->nType & (JX9_TK_SEMI/*';'*/|JX9_TK_COLON/*;'*/) && iNest < 1 ){ - break; - } - pEnd++; - } - if( pGen->pIn >= pEnd ){ - rc = jx9GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, "Empty case expression"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - } - /* Swap token stream */ - pTmp = pGen->pEnd; - pGen->pEnd = pEnd; - pInstrContainer = jx9VmGetByteCodeContainer(pGen->pVm); - jx9VmSetByteCodeContainer(pGen->pVm, &pExpr->aByteCode); - rc = jx9CompileExpr(&(*pGen), 0, 0); - /* Emit the done instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); - jx9VmSetByteCodeContainer(pGen->pVm, pInstrContainer); - /* Update token stream */ - pGen->pIn = pEnd; - pGen->pEnd = pTmp; - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - return SXRET_OK; -} -/* - * Compile the smart switch statement. - * According to the JX9 language reference manual - * The switch statement is similar to a series of IF statements on the same expression. - * In many occasions, you may want to compare the same variable (or expression) with many - * different values, and execute a different piece of code depending on which value it equals to. - * This is exactly what the switch statement is for. - * Note: Note that unlike some other languages, the continue statement applies to switch and acts - * similar to break. If you have a switch inside a loop and wish to continue to the next iteration - * of the outer loop, use continue 2. - * Note that switch/case does loose comparision. - * It is important to understand how the switch statement is executed in order to avoid mistakes. - * The switch statement executes line by line (actually, statement by statement). - * In the beginning, no code is executed. Only when a case statement is found with a value that - * matches the value of the switch expression does JX9 begin to execute the statements. - * JX9 continues to execute the statements until the end of the switch block, or the first time - * it sees a break statement. If you don't write a break statement at the end of a case's statement list. - * In a switch statement, the condition is evaluated only once and the result is compared to each - * case statement. In an elseif statement, the condition is evaluated again. If your condition - * is more complicated than a simple compare and/or is in a tight loop, a switch may be faster. - * The statement list for a case can also be empty, which simply passes control into the statement - * list for the next case. - * The case expression may be any expression that evaluates to a simple type, that is, integer - * or floating-point numbers and strings. - */ -static sxi32 jx9CompileSwitch(jx9_gen_state *pGen) -{ - GenBlock *pSwitchBlock; - SyToken *pTmp, *pEnd; - jx9_switch *pSwitch; - sxu32 nLine; - sxi32 rc; - nLine = pGen->pIn->nLine; - /* Jump the 'switch' keyword */ - pGen->pIn++; - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_LPAREN) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Expected '(' after 'switch' keyword"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - goto Synchronize; - } - /* Jump the left parenthesis '(' */ - pGen->pIn++; - pEnd = 0; /* cc warning */ - /* Create the loop block */ - rc = GenStateEnterBlock(&(*pGen), GEN_BLOCK_LOOP|GEN_BLOCK_SWITCH, - jx9VmInstrLength(pGen->pVm), 0, &pSwitchBlock); - if( rc != SXRET_OK ){ - return SXERR_ABORT; - } - /* Delimit the condition */ - jx9DelimitNestedTokens(pGen->pIn, pGen->pEnd, JX9_TK_LPAREN /* '(' */, JX9_TK_RPAREN /* ')' */, &pEnd); - if( pGen->pIn == pEnd || pEnd >= pGen->pEnd ){ - /* Empty expression */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Expected expression after 'switch' keyword"); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - } - /* Swap token streams */ - pTmp = pGen->pEnd; - pGen->pEnd = pEnd; - /* Compile the expression */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc == SXERR_ABORT ){ - /* Expression handler request an operation abort [i.e: Out-of-memory] */ - return SXERR_ABORT; - } - /* Update token stream */ - while(pGen->pIn < pEnd ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, - "Switch: Unexpected token '%z'", &pGen->pIn->sData); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - pGen->pIn++; - } - pGen->pIn = &pEnd[1]; - pGen->pEnd = pTmp; - if( pGen->pIn >= pGen->pEnd || &pGen->pIn[1] >= pGen->pEnd || - (pGen->pIn->nType & (JX9_TK_OCB/*'{'*/|JX9_TK_COLON/*:*/)) == 0 ){ - pTmp = pGen->pIn; - if( pTmp >= pGen->pEnd ){ - pTmp--; - } - /* Unexpected token */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pTmp->nLine, "Switch: Unexpected token '%z'", &pTmp->sData); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - goto Synchronize; - } - pGen->pIn++; /* Jump the leading curly braces/colons */ - /* Create the switch blocks container */ - pSwitch = (jx9_switch *)SyMemBackendAlloc(&pGen->pVm->sAllocator, sizeof(jx9_switch)); - if( pSwitch == 0 ){ - /* Abort compilation */ - return GenStateOutOfMem(pGen); - } - /* Zero the structure */ - SyZero(pSwitch, sizeof(jx9_switch)); - /* Initialize fields */ - SySetInit(&pSwitch->aCaseExpr, &pGen->pVm->sAllocator, sizeof(jx9_case_expr)); - /* Emit the switch instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_SWITCH, 0, 0, pSwitch, 0); - /* Compile case blocks */ - for(;;){ - sxu32 nKwrd; - if( pGen->pIn >= pGen->pEnd ){ - /* No more input to process */ - break; - } - if( (pGen->pIn->nType & JX9_TK_KEYWORD) == 0 ){ - if( (pGen->pIn->nType & JX9_TK_CCB /*}*/) == 0 ){ - /* Unexpected token */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Switch: Unexpected token '%z'", - &pGen->pIn->sData); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - /* FALL THROUGH */ - } - /* Block compiled */ - break; - } - /* Extract the keyword */ - nKwrd = SX_PTR_TO_INT(pGen->pIn->pUserData); - if( nKwrd == JX9_TKWRD_DEFAULT ){ - /* - * Accroding to the JX9 language reference manual - * A special case is the default case. This case matches anything - * that wasn't matched by the other cases. - */ - if( pSwitch->nDefault > 0 ){ - /* Default case already compiled */ - rc = jx9GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, "Switch: 'default' case already compiled"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - } - pGen->pIn++; /* Jump the 'default' keyword */ - /* Compile the default block */ - rc = GenStateCompileSwitchBlock(pGen,&pSwitch->nDefault); - if( rc == SXERR_ABORT){ - return SXERR_ABORT; - }else if( rc == SXERR_EOF ){ - break; - } - }else if( nKwrd == JX9_TKWRD_CASE ){ - jx9_case_expr sCase; - /* Standard case block */ - pGen->pIn++; /* Jump the 'case' keyword */ - /* initialize the structure */ - SySetInit(&sCase.aByteCode, &pGen->pVm->sAllocator, sizeof(VmInstr)); - /* Compile the case expression */ - rc = GenStateCompileCaseExpr(pGen, &sCase); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - /* Compile the case block */ - rc = GenStateCompileSwitchBlock(pGen,&sCase.nStart); - /* Insert in the switch container */ - SySetPut(&pSwitch->aCaseExpr, (const void *)&sCase); - if( rc == SXERR_ABORT){ - return SXERR_ABORT; - }else if( rc == SXERR_EOF ){ - break; - } - }else{ - /* Unexpected token */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Switch: Unexpected token '%z'", - &pGen->pIn->sData); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - break; - } - } - /* Fix all jumps now the destination is resolved */ - pSwitch->nOut = jx9VmInstrLength(pGen->pVm); - GenStateFixJumps(pSwitchBlock, -1, jx9VmInstrLength(pGen->pVm)); - /* Release the loop block */ - GenStateLeaveBlock(pGen, 0); - if( pGen->pIn < pGen->pEnd ){ - /* Jump the trailing curly braces */ - pGen->pIn++; - } - /* Statement successfully compiled */ - return SXRET_OK; -Synchronize: - /* Synchronize with the first semi-colon */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; -} -/* - * Process default argument values. That is, a function may define C++-style default value - * as follows: - * function makecoffee($type = "cappuccino") - * { - * return "Making a cup of $type.\n"; - * } - * Some features: - * 1 -) Default arguments value can be any complex expression [i.e: function call, annynoymous - * functions, array member, ..] - * 2 -) Full type hinting: (Arguments are automatically casted to the desired type) - * Example: - * function a(string $a){} function b(int $a, string $c, float $d){} - * 3 -) Function overloading!! - * Example: - * function foo($a) { - * return $a.JX9_EOL; - * } - * function foo($a, $b) { - * return $a + $b; - * } - * print foo(5); // Prints "5" - * print foo(5, 2); // Prints "7" - * // Same arg - * function foo(string $a) - * { - * print "a is a string\n"; - * dump($a); - * } - * function foo(int $a) - * { - * print "a is integer\n"; - * dump($a); - * } - * function foo(array $a) - * { - * print "a is an array\n"; - * dump($a); - * } - * foo('This is a great feature'); // a is a string [first foo] - * foo(52); // a is integer [second foo] - * foo(array(14, __TIME__, __DATE__)); // a is an array [third foo] - * Please refer to the official documentation for more information on the powerful extension - * introduced by the JX9 engine. - */ -static sxi32 GenStateProcessArgValue(jx9_gen_state *pGen, jx9_vm_func_arg *pArg, SyToken *pIn, SyToken *pEnd) -{ - SyToken *pTmpIn, *pTmpEnd; - SySet *pInstrContainer; - sxi32 rc; - /* Swap token stream */ - SWAP_DELIMITER(pGen, pIn, pEnd); - pInstrContainer = jx9VmGetByteCodeContainer(pGen->pVm); - jx9VmSetByteCodeContainer(pGen->pVm, &pArg->aByteCode); - /* Compile the expression holding the argument value */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - /* Emit the done instruction */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_DONE, (rc != SXERR_EMPTY ? 1 : 0), 0, 0, 0); - jx9VmSetByteCodeContainer(pGen->pVm, pInstrContainer); - RE_SWAP_DELIMITER(pGen); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - return SXRET_OK; -} -/* - * Collect function arguments one after one. - * According to the JX9 language reference manual. - * Information may be passed to functions via the argument list, which is a comma-delimited - * list of expressions. - * JX9 supports passing arguments by value (the default), passing by reference - * and default argument values. Variable-length argument lists are also supported, - * see also the function references for func_num_args(), func_get_arg(), and func_get_args() - * for more information. - * Example #1 Passing arrays to functions - * - * Making arguments be passed by reference - * By default, function arguments are passed by value (so that if the value of the argument - * within the function is changed, it does not get changed outside of the function). - * To allow a function to modify its arguments, they must be passed by reference. - * To have an argument to a function always passed by reference, prepend an ampersand (&) - * to the argument name in the function definition: - * Example #2 Passing function parameters by reference - * - * - * JX9 have introduced powerful extension including full type hinting, function overloading - * complex agrument values.Please refer to the official documentation for more information - * on these extension. - */ -static sxi32 GenStateCollectFuncArgs(jx9_vm_func *pFunc, jx9_gen_state *pGen, SyToken *pEnd) -{ - jx9_vm_func_arg sArg; /* Current processed argument */ - SyToken *pCur, *pIn; /* Token stream */ - SyBlob sSig; /* Function signature */ - char *zDup; /* Copy of argument name */ - sxi32 rc; - - pIn = pGen->pIn; - pCur = 0; - SyBlobInit(&sSig, &pGen->pVm->sAllocator); - /* Process arguments one after one */ - for(;;){ - if( pIn >= pEnd ){ - /* No more arguments to process */ - break; - } - SyZero(&sArg, sizeof(jx9_vm_func_arg)); - SySetInit(&sArg.aByteCode, &pGen->pVm->sAllocator, sizeof(VmInstr)); - if( pIn->nType & (JX9_TK_ID|JX9_TK_KEYWORD) ){ - if( pIn->nType & JX9_TK_KEYWORD ){ - sxu32 nKey = (sxu32)(SX_PTR_TO_INT(pIn->pUserData)); - if( nKey & JX9_TKWRD_BOOL ){ - sArg.nType = MEMOBJ_BOOL; - }else if( nKey & JX9_TKWRD_INT ){ - sArg.nType = MEMOBJ_INT; - }else if( nKey & JX9_TKWRD_STRING ){ - sArg.nType = MEMOBJ_STRING; - }else if( nKey & JX9_TKWRD_FLOAT ){ - sArg.nType = MEMOBJ_REAL; - }else{ - jx9GenCompileError(&(*pGen), E_WARNING, pGen->pIn->nLine, - "Invalid argument type '%z', Automatic cast will not be performed", - &pIn->sData); - } - } - pIn++; - } - if( pIn >= pEnd ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Missing argument name"); - return rc; - } - if( pIn >= pEnd || (pIn->nType & JX9_TK_DOLLAR) == 0 || &pIn[1] >= pEnd || (pIn[1].nType & (JX9_TK_ID|JX9_TK_KEYWORD)) == 0 ){ - /* Invalid argument */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pGen->pIn->nLine, "Invalid argument name"); - return rc; - } - pIn++; /* Jump the dollar sign */ - /* Copy argument name */ - zDup = SyMemBackendStrDup(&pGen->pVm->sAllocator, SyStringData(&pIn->sData), SyStringLength(&pIn->sData)); - if( zDup == 0 ){ - return GenStateOutOfMem(pGen); - } - SyStringInitFromBuf(&sArg.sName, zDup, SyStringLength(&pIn->sData)); - pIn++; - if( pIn < pEnd ){ - if( pIn->nType & JX9_TK_EQUAL ){ - SyToken *pDefend; - sxi32 iNest = 0; - pIn++; /* Jump the equal sign */ - pDefend = pIn; - /* Process the default value associated with this argument */ - while( pDefend < pEnd ){ - if( (pDefend->nType & JX9_TK_COMMA) && iNest <= 0 ){ - break; - } - if( pDefend->nType & (JX9_TK_LPAREN/*'('*/|JX9_TK_OCB/*'{'*/|JX9_TK_OSB/*[*/) ){ - /* Increment nesting level */ - iNest++; - }else if( pDefend->nType & (JX9_TK_RPAREN/*')'*/|JX9_TK_CCB/*'}'*/|JX9_TK_CSB/*]*/) ){ - /* Decrement nesting level */ - iNest--; - } - pDefend++; - } - if( pIn >= pDefend ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pIn->nLine, "Missing argument default value"); - return rc; - } - /* Process default value */ - rc = GenStateProcessArgValue(&(*pGen), &sArg, pIn, pDefend); - if( rc != SXRET_OK ){ - return rc; - } - /* Point beyond the default value */ - pIn = pDefend; - } - if( pIn < pEnd && (pIn->nType & JX9_TK_COMMA) == 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pIn->nLine, "Unexpected token '%z'", &pIn->sData); - return rc; - } - pIn++; /* Jump the trailing comma */ - } - /* Append argument signature */ - if( sArg.nType > 0 ){ - int c; - c = 'n'; /* cc warning */ - /* Type leading character */ - switch(sArg.nType){ - case MEMOBJ_HASHMAP: - /* Hashmap aka 'array' */ - c = 'h'; - break; - case MEMOBJ_INT: - /* Integer */ - c = 'i'; - break; - case MEMOBJ_BOOL: - /* Bool */ - c = 'b'; - break; - case MEMOBJ_REAL: - /* Float */ - c = 'f'; - break; - case MEMOBJ_STRING: - /* String */ - c = 's'; - break; - default: - break; - } - SyBlobAppend(&sSig, (const void *)&c, sizeof(char)); - } - /* Save in the argument set */ - SySetPut(&pFunc->aArgs, (const void *)&sArg); - } - if( SyBlobLength(&sSig) > 0 ){ - /* Save function signature */ - SyStringInitFromBuf(&pFunc->sSignature, SyBlobData(&sSig), SyBlobLength(&sSig)); - } - return SXRET_OK; -} -/* - * Compile function [i.e: standard function, annonymous function or closure ] body. - * Return SXRET_OK on success. Any other return value indicates failure - * and this routine takes care of generating the appropriate error message. - */ -static sxi32 GenStateCompileFuncBody( - jx9_gen_state *pGen, /* Code generator state */ - jx9_vm_func *pFunc /* Function state */ - ) -{ - SySet *pInstrContainer; /* Instruction container */ - GenBlock *pBlock; - sxi32 rc; - /* Attach the new function */ - rc = GenStateEnterBlock(&(*pGen), GEN_BLOCK_PROTECTED|GEN_BLOCK_FUNC,jx9VmInstrLength(pGen->pVm), pFunc, &pBlock); - if( rc != SXRET_OK ){ - return GenStateOutOfMem(pGen); - } - /* Swap bytecode containers */ - pInstrContainer = jx9VmGetByteCodeContainer(pGen->pVm); - jx9VmSetByteCodeContainer(pGen->pVm, &pFunc->aByteCode); - /* Compile the body */ - jx9CompileBlock(&(*pGen)); - /* Emit the final return if not yet done */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_DONE, 0, 0, 0, 0); - /* Restore the default container */ - jx9VmSetByteCodeContainer(pGen->pVm, pInstrContainer); - /* Leave function block */ - GenStateLeaveBlock(&(*pGen), 0); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - /* All done, function body compiled */ - return SXRET_OK; -} -/* - * Compile a JX9 function whether is a Standard or Annonymous function. - * According to the JX9 language reference manual. - * Function names follow the same rules as other labels in JX9. A valid function name - * starts with a letter or underscore, followed by any number of letters, numbers, or - * underscores. As a regular expression, it would be expressed thus: - * [a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*. - * Functions need not be defined before they are referenced. - * All functions and objectes in JX9 have the global scope - they can be called outside - * a function even if they were defined inside and vice versa. - * It is possible to call recursive functions in JX9. However avoid recursive function/method - * calls with over 32-64 recursion levels. - * - * JX9 have introduced powerful extension including full type hinting, function overloading, - * complex agrument values and more. Please refer to the official documentation for more information - * on these extension. - */ -static sxi32 GenStateCompileFunc( - jx9_gen_state *pGen, /* Code generator state */ - SyString *pName, /* Function name. NULL otherwise */ - sxi32 iFlags, /* Control flags */ - jx9_vm_func **ppFunc /* OUT: function state */ - ) -{ - jx9_vm_func *pFunc; - SyToken *pEnd; - sxu32 nLine; - char *zName; - sxi32 rc; - /* Extract line number */ - nLine = pGen->pIn->nLine; - /* Jump the left parenthesis '(' */ - pGen->pIn++; - /* Delimit the function signature */ - jx9DelimitNestedTokens(pGen->pIn, pGen->pEnd, JX9_TK_LPAREN /* '(' */, JX9_TK_RPAREN /* ')' */, &pEnd); - if( pEnd >= pGen->pEnd ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Missing ')' after function '%z' signature", pName); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - pGen->pIn = pGen->pEnd; - return SXRET_OK; - } - /* Create the function state */ - pFunc = (jx9_vm_func *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(jx9_vm_func)); - if( pFunc == 0 ){ - goto OutOfMem; - } - /* function ID */ - zName = SyMemBackendStrDup(&pGen->pVm->sAllocator, pName->zString, pName->nByte); - if( zName == 0 ){ - /* Don't worry about freeing memory, everything will be released shortly */ - goto OutOfMem; - } - /* Initialize the function state */ - jx9VmInitFuncState(pGen->pVm, pFunc, zName, pName->nByte, iFlags, 0); - if( pGen->pIn < pEnd ){ - /* Collect function arguments */ - rc = GenStateCollectFuncArgs(pFunc, &(*pGen), pEnd); - if( rc == SXERR_ABORT ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return SXERR_ABORT; - } - } - /* Compile function body */ - pGen->pIn = &pEnd[1]; - /* Compile the body */ - rc = GenStateCompileFuncBody(&(*pGen), pFunc); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - if( ppFunc ){ - *ppFunc = pFunc; - } - /* Finally register the function */ - rc = jx9VmInstallUserFunction(pGen->pVm, pFunc, 0); - return rc; - /* Fall through if something goes wrong */ -OutOfMem: - /* If the supplied memory subsystem is so sick that we are unable to allocate - * a tiny chunk of memory, there is no much we can do here. - */ - return GenStateOutOfMem(pGen); -} -/* - * Compile a standard JX9 function. - * Refer to the block-comment above for more information. - */ -static sxi32 jx9CompileFunction(jx9_gen_state *pGen) -{ - SyString *pName; - sxi32 iFlags; - sxu32 nLine; - sxi32 rc; - - nLine = pGen->pIn->nLine; - pGen->pIn++; /* Jump the 'function' keyword */ - iFlags = 0; - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & (JX9_TK_ID|JX9_TK_KEYWORD)) == 0 ){ - /* Invalid function name */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Invalid function name"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - /* Sychronize with the next semi-colon or braces*/ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (JX9_TK_SEMI|JX9_TK_OCB)) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; - } - pName = &pGen->pIn->sData; - nLine = pGen->pIn->nLine; - /* Jump the function name */ - pGen->pIn++; - if( pGen->pIn >= pGen->pEnd || (pGen->pIn->nType & JX9_TK_LPAREN) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, nLine, "Expected '(' after function name '%z'", pName); - if( rc == SXERR_ABORT ){ - /* Error count limit reached, abort immediately */ - return SXERR_ABORT; - } - /* Sychronize with the next semi-colon or '{' */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & (JX9_TK_SEMI|JX9_TK_OCB)) == 0 ){ - pGen->pIn++; - } - return SXRET_OK; - } - /* Compile function body */ - rc = GenStateCompileFunc(&(*pGen),pName,iFlags,0); - return rc; -} -/* - * Generate bytecode for a given expression tree. - * If something goes wrong while generating bytecode - * for the expression tree (A very unlikely scenario) - * this function takes care of generating the appropriate - * error message. - */ -static sxi32 GenStateEmitExprCode( - jx9_gen_state *pGen, /* Code generator state */ - jx9_expr_node *pNode, /* Root of the expression tree */ - sxi32 iFlags /* Control flags */ - ) -{ - VmInstr *pInstr; - sxu32 nJmpIdx; - sxi32 iP1 = 0; - sxu32 iP2 = 0; - void *p3 = 0; - sxi32 iVmOp; - sxi32 rc; - if( pNode->xCode ){ - SyToken *pTmpIn, *pTmpEnd; - /* Compile node */ - SWAP_DELIMITER(pGen, pNode->pStart, pNode->pEnd); - rc = pNode->xCode(&(*pGen), iFlags); - RE_SWAP_DELIMITER(pGen); - return rc; - } - if( pNode->pOp == 0 ){ - jx9GenCompileError(&(*pGen), E_ERROR, pNode->pStart->nLine, - "Invalid expression node, JX9 is aborting compilation"); - return SXERR_ABORT; - } - iVmOp = pNode->pOp->iVmOp; - if( pNode->pOp->iOp == EXPR_OP_QUESTY ){ - sxu32 nJz, nJmp; - /* Ternary operator require special handling */ - /* Phase#1: Compile the condition */ - rc = GenStateEmitExprCode(&(*pGen), pNode->pCond, iFlags); - if( rc != SXRET_OK ){ - return rc; - } - nJz = nJmp = 0; /* cc -O6 warning */ - /* Phase#2: Emit the false jump */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JZ, 0, 0, 0, &nJz); - if( pNode->pLeft ){ - /* Phase#3: Compile the 'then' expression */ - rc = GenStateEmitExprCode(&(*pGen), pNode->pLeft, iFlags); - if( rc != SXRET_OK ){ - return rc; - } - } - /* Phase#4: Emit the unconditional jump */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JMP, 0, 0, 0, &nJmp); - /* Phase#5: Fix the false jump now the jump destination is resolved. */ - pInstr = jx9VmGetInstr(pGen->pVm, nJz); - if( pInstr ){ - pInstr->iP2 = jx9VmInstrLength(pGen->pVm); - } - /* Phase#6: Compile the 'else' expression */ - if( pNode->pRight ){ - rc = GenStateEmitExprCode(&(*pGen), pNode->pRight, iFlags); - if( rc != SXRET_OK ){ - return rc; - } - } - if( nJmp > 0 ){ - /* Phase#7: Fix the unconditional jump */ - pInstr = jx9VmGetInstr(pGen->pVm, nJmp); - if( pInstr ){ - pInstr->iP2 = jx9VmInstrLength(pGen->pVm); - } - } - /* All done */ - return SXRET_OK; - } - /* Generate code for the left tree */ - if( pNode->pLeft ){ - if( iVmOp == JX9_OP_CALL ){ - jx9_expr_node **apNode; - sxi32 n; - /* Recurse and generate bytecodes for function arguments */ - apNode = (jx9_expr_node **)SySetBasePtr(&pNode->aNodeArgs); - /* Read-only load */ - iFlags |= EXPR_FLAG_RDONLY_LOAD; - for( n = 0 ; n < (sxi32)SySetUsed(&pNode->aNodeArgs) ; ++n ){ - rc = GenStateEmitExprCode(&(*pGen), apNode[n], iFlags&~EXPR_FLAG_LOAD_IDX_STORE); - if( rc != SXRET_OK ){ - return rc; - } - } - /* Total number of given arguments */ - iP1 = (sxi32)SySetUsed(&pNode->aNodeArgs); - /* Remove stale flags now */ - iFlags &= ~EXPR_FLAG_RDONLY_LOAD; - } - rc = GenStateEmitExprCode(&(*pGen), pNode->pLeft, iFlags); - if( rc != SXRET_OK ){ - return rc; - } - if( iVmOp == JX9_OP_CALL ){ - pInstr = jx9VmPeekInstr(pGen->pVm); - if( pInstr ){ - if ( pInstr->iOp == JX9_OP_LOADC ){ - /* Prevent constant expansion */ - pInstr->iP1 = 0; - }else if( pInstr->iOp == JX9_OP_MEMBER /* $a.b(1, 2, 3) */ ){ - /* Annonymous function call, flag that */ - pInstr->iP2 = 1; - } - } - }else if( iVmOp == JX9_OP_LOAD_IDX ){ - jx9_expr_node **apNode; - sxi32 n; - /* Recurse and generate bytecodes for array index */ - apNode = (jx9_expr_node **)SySetBasePtr(&pNode->aNodeArgs); - for( n = 0 ; n < (sxi32)SySetUsed(&pNode->aNodeArgs) ; ++n ){ - rc = GenStateEmitExprCode(&(*pGen), apNode[n], iFlags&~EXPR_FLAG_LOAD_IDX_STORE); - if( rc != SXRET_OK ){ - return rc; - } - } - if( SySetUsed(&pNode->aNodeArgs) > 0 ){ - iP1 = 1; /* Node have an index associated with it */ - } - if( iFlags & EXPR_FLAG_LOAD_IDX_STORE ){ - /* Create an empty entry when the desired index is not found */ - iP2 = 1; - } - }else if( pNode->pOp->iOp == EXPR_OP_COMMA ){ - /* POP the left node */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_POP, 1, 0, 0, 0); - } - } - rc = SXRET_OK; - nJmpIdx = 0; - /* Generate code for the right tree */ - if( pNode->pRight ){ - if( iVmOp == JX9_OP_LAND ){ - /* Emit the false jump so we can short-circuit the logical and */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JZ, 1/* Keep the value on the stack */, 0, 0, &nJmpIdx); - }else if (iVmOp == JX9_OP_LOR ){ - /* Emit the true jump so we can short-circuit the logical or*/ - jx9VmEmitInstr(pGen->pVm, JX9_OP_JNZ, 1/* Keep the value on the stack */, 0, 0, &nJmpIdx); - }else if( pNode->pOp->iPrec == 18 /* Combined binary operators [i.e: =, '.=', '+=', *=' ...] precedence */ ){ - iFlags |= EXPR_FLAG_LOAD_IDX_STORE; - } - rc = GenStateEmitExprCode(&(*pGen), pNode->pRight, iFlags); - if( iVmOp == JX9_OP_STORE ){ - pInstr = jx9VmPeekInstr(pGen->pVm); - if( pInstr ){ - if(pInstr->iOp == JX9_OP_MEMBER ){ - /* Perform a member store operation [i.e: $this.x = 50] */ - iP2 = 1; - }else{ - if( pInstr->iOp == JX9_OP_LOAD_IDX ){ - /* Transform the STORE instruction to STORE_IDX instruction */ - iVmOp = JX9_OP_STORE_IDX; - iP1 = pInstr->iP1; - }else{ - p3 = pInstr->p3; - } - /* POP the last dynamic load instruction */ - (void)jx9VmPopInstr(pGen->pVm); - } - } - } - } - if( iVmOp > 0 ){ - if( iVmOp == JX9_OP_INCR || iVmOp == JX9_OP_DECR ){ - if( pNode->iFlags & EXPR_NODE_PRE_INCR ){ - /* Pre-increment/decrement operator [i.e: ++$i, --$j ] */ - iP1 = 1; - } - } - /* Finally, emit the VM instruction associated with this operator */ - jx9VmEmitInstr(pGen->pVm, iVmOp, iP1, iP2, p3, 0); - if( nJmpIdx > 0 ){ - /* Fix short-circuited jumps now the destination is resolved */ - pInstr = jx9VmGetInstr(pGen->pVm, nJmpIdx); - if( pInstr ){ - pInstr->iP2 = jx9VmInstrLength(pGen->pVm); - } - } - } - return rc; -} -/* - * Compile a JX9 expression. - * According to the JX9 language reference manual: - * Expressions are the most important building stones of JX9. - * In JX9, almost anything you write is an expression. - * The simplest yet most accurate way to define an expression - * is "anything that has a value". - * If something goes wrong while compiling the expression, this - * function takes care of generating the appropriate error - * message. - */ -static sxi32 jx9CompileExpr( - jx9_gen_state *pGen, /* Code generator state */ - sxi32 iFlags, /* Control flags */ - sxi32 (*xTreeValidator)(jx9_gen_state *, jx9_expr_node *) /* Node validator callback.NULL otherwise */ - ) -{ - jx9_expr_node *pRoot; - SySet sExprNode; - SyToken *pEnd; - sxi32 nExpr; - sxi32 iNest; - sxi32 rc; - /* Initialize worker variables */ - nExpr = 0; - pRoot = 0; - SySetInit(&sExprNode, &pGen->pVm->sAllocator, sizeof(jx9_expr_node *)); - SySetAlloc(&sExprNode, 0x10); - rc = SXRET_OK; - /* Delimit the expression */ - pEnd = pGen->pIn; - iNest = 0; - while( pEnd < pGen->pEnd ){ - if( pEnd->nType & JX9_TK_OCB /* '{' */ ){ - /* Ticket 1433-30: Annonymous/Closure functions body */ - iNest++; - }else if(pEnd->nType & JX9_TK_CCB /* '}' */ ){ - iNest--; - }else if( pEnd->nType & JX9_TK_SEMI /* ';' */ ){ - if( iNest <= 0 ){ - break; - } - } - pEnd++; - } - if( iFlags & EXPR_FLAG_COMMA_STATEMENT ){ - SyToken *pEnd2 = pGen->pIn; - iNest = 0; - /* Stop at the first comma */ - while( pEnd2 < pEnd ){ - if( pEnd2->nType & (JX9_TK_OCB/*'{'*/|JX9_TK_OSB/*'['*/|JX9_TK_LPAREN/*'('*/) ){ - iNest++; - }else if(pEnd2->nType & (JX9_TK_CCB/*'}'*/|JX9_TK_CSB/*']'*/|JX9_TK_RPAREN/*')'*/)){ - iNest--; - }else if( pEnd2->nType & JX9_TK_COMMA /*','*/ ){ - if( iNest <= 0 ){ - break; - } - } - pEnd2++; - } - if( pEnd2 pGen->pIn ){ - SyToken *pTmp = pGen->pEnd; - /* Swap delimiter */ - pGen->pEnd = pEnd; - /* Try to get an expression tree */ - rc = jx9ExprMakeTree(&(*pGen), &sExprNode, &pRoot); - if( rc == SXRET_OK && pRoot ){ - rc = SXRET_OK; - if( xTreeValidator ){ - /* Call the upper layer validator callback */ - rc = xTreeValidator(&(*pGen), pRoot); - } - if( rc != SXERR_ABORT ){ - /* Generate code for the given tree */ - rc = GenStateEmitExprCode(&(*pGen), pRoot, iFlags); - } - nExpr = 1; - } - /* Release the whole tree */ - jx9ExprFreeTree(&(*pGen), &sExprNode); - /* Synchronize token stream */ - pGen->pEnd = pTmp; - pGen->pIn = pEnd; - if( rc == SXERR_ABORT ){ - SySetRelease(&sExprNode); - return SXERR_ABORT; - } - } - SySetRelease(&sExprNode); - return nExpr > 0 ? SXRET_OK : SXERR_EMPTY; -} -/* - * Return a pointer to the node construct handler associated - * with a given node type [i.e: string, integer, float, ...]. - */ -JX9_PRIVATE ProcNodeConstruct jx9GetNodeHandler(sxu32 nNodeType) -{ - if( nNodeType & JX9_TK_NUM ){ - /* Numeric literal: Either real or integer */ - return jx9CompileNumLiteral; - }else if( nNodeType & JX9_TK_DSTR ){ - /* Double quoted string */ - return jx9CompileString; - }else if( nNodeType & JX9_TK_SSTR ){ - /* Single quoted string */ - return jx9CompileSimpleString; - }else if( nNodeType & JX9_TK_NOWDOC ){ - /* Nowdoc */ - return jx9CompileNowdoc; - } - return 0; -} -/* - * Jx9 Language construct table. - */ -static const LangConstruct aLangConstruct[] = { - { JX9_TKWRD_IF, jx9CompileIf }, - { JX9_TKWRD_FUNCTION, jx9CompileFunction }, - { JX9_TKWRD_FOREACH, jx9CompileForeach }, - { JX9_TKWRD_WHILE, jx9CompileWhile }, - { JX9_TKWRD_FOR, jx9CompileFor }, - { JX9_TKWRD_SWITCH, jx9CompileSwitch }, - { JX9_TKWRD_DIE, jx9CompileHalt }, - { JX9_TKWRD_EXIT, jx9CompileHalt }, - { JX9_TKWRD_RETURN, jx9CompileReturn }, - { JX9_TKWRD_BREAK, jx9CompileBreak }, - { JX9_TKWRD_CONTINUE, jx9CompileContinue }, - { JX9_TKWRD_STATIC, jx9CompileStatic }, - { JX9_TKWRD_UPLINK, jx9CompileUplink }, - { JX9_TKWRD_CONST, jx9CompileConstant }, -}; -/* - * Return a pointer to the statement handler routine associated - * with a given JX9 keyword [i.e: if, for, while, ...]. - */ -static ProcLangConstruct GenStateGetStatementHandler( - sxu32 nKeywordID /* Keyword ID*/ - ) -{ - sxu32 n = 0; - for(;;){ - if( n >= SX_ARRAYSIZE(aLangConstruct) ){ - break; - } - if( aLangConstruct[n].nID == nKeywordID ){ - /* Return a pointer to the handler. - */ - return aLangConstruct[n].xConstruct; - } - n++; - } - /* Not a language construct */ - return 0; -} -/* - * Compile a jx9 program. - * If something goes wrong while compiling the Jx9 chunk, this function - * takes care of generating the appropriate error message. - */ -static sxi32 GenStateCompileChunk( - jx9_gen_state *pGen, /* Code generator state */ - sxi32 iFlags /* Compile flags */ - ) -{ - ProcLangConstruct xCons; - sxi32 rc; - rc = SXRET_OK; /* Prevent compiler warning */ - for(;;){ - if( pGen->pIn >= pGen->pEnd ){ - /* No more input to process */ - break; - } - xCons = 0; - if( pGen->pIn->nType & JX9_TK_KEYWORD ){ - sxu32 nKeyword = (sxu32)SX_PTR_TO_INT(pGen->pIn->pUserData); - /* Try to extract a language construct handler */ - xCons = GenStateGetStatementHandler(nKeyword); - if( xCons == 0 && !jx9IsLangConstruct(nKeyword) ){ - rc = jx9GenCompileError(pGen, E_ERROR, pGen->pIn->nLine, - "Syntax error: Unexpected keyword '%z'", - &pGen->pIn->sData); - if( rc == SXERR_ABORT ){ - break; - } - /* Synchronize with the first semi-colon and avoid compiling - * this erroneous statement. - */ - xCons = jx9ErrorRecover; - } - } - if( xCons == 0 ){ - /* Assume an expression an try to compile it */ - rc = jx9CompileExpr(&(*pGen), 0, 0); - if( rc != SXERR_EMPTY ){ - /* Pop l-value */ - jx9VmEmitInstr(pGen->pVm, JX9_OP_POP, 1, 0, 0, 0); - } - }else{ - /* Go compile the sucker */ - rc = xCons(&(*pGen)); - } - if( rc == SXERR_ABORT ){ - /* Request to abort compilation */ - break; - } - /* Ignore trailing semi-colons ';' */ - while( pGen->pIn < pGen->pEnd && (pGen->pIn->nType & JX9_TK_SEMI) ){ - pGen->pIn++; - } - if( iFlags & JX9_COMPILE_SINGLE_STMT ){ - /* Compile a single statement and return */ - break; - } - /* LOOP ONE */ - /* LOOP TWO */ - /* LOOP THREE */ - /* LOOP FOUR */ - } - /* Return compilation status */ - return rc; -} -/* - * Compile a raw chunk. The raw chunk can contain JX9 code embedded - * in HTML, XML and so on. This function handle all the stuff. - * This is the only compile interface exported from this file. - */ -JX9_PRIVATE sxi32 jx9CompileScript( - jx9_vm *pVm, /* Generate JX9 bytecodes for this Virtual Machine */ - SyString *pScript, /* Script to compile */ - sxi32 iFlags /* Compile flags */ - ) -{ - jx9_gen_state *pGen; - SySet aToken; - sxi32 rc; - if( pScript->nByte < 1 ){ - /* Nothing to compile */ - return JX9_OK; - } - /* Initialize the tokens containers */ - SySetInit(&aToken, &pVm->sAllocator, sizeof(SyToken)); - SySetAlloc(&aToken, 0xc0); - pGen = &pVm->sCodeGen; - rc = JX9_OK; - /* Tokenize the JX9 chunk first */ - jx9Tokenize(pScript->zString,pScript->nByte,&aToken); - if( SySetUsed(&aToken) < 1 ){ - return SXERR_EMPTY; - } - /* Point to the head and tail of the token stream. */ - pGen->pIn = (SyToken *)SySetBasePtr(&aToken); - pGen->pEnd = &pGen->pIn[SySetUsed(&aToken)]; - /* Compile the chunk */ - rc = GenStateCompileChunk(pGen,iFlags); - /* Cleanup */ - SySetRelease(&aToken); - return rc; -} -/* - * Utility routines.Initialize the code generator. - */ -JX9_PRIVATE sxi32 jx9InitCodeGenerator( - jx9_vm *pVm, /* Target VM */ - ProcConsumer xErr, /* Error log consumer callabck */ - void *pErrData /* Last argument to xErr() */ - ) -{ - jx9_gen_state *pGen = &pVm->sCodeGen; - /* Zero the structure */ - SyZero(pGen, sizeof(jx9_gen_state)); - /* Initial state */ - pGen->pVm = &(*pVm); - pGen->xErr = xErr; - pGen->pErrData = pErrData; - SyHashInit(&pGen->hLiteral, &pVm->sAllocator, 0, 0); - SyHashInit(&pGen->hVar, &pVm->sAllocator, 0, 0); - /* Create the global scope */ - GenStateInitBlock(pGen, &pGen->sGlobal,GEN_BLOCK_GLOBAL,jx9VmInstrLength(&(*pVm)), 0); - /* Point to the global scope */ - pGen->pCurrent = &pGen->sGlobal; - return SXRET_OK; -} -/* - * Utility routines. Reset the code generator to it's initial state. - */ -JX9_PRIVATE sxi32 jx9ResetCodeGenerator( - jx9_vm *pVm, /* Target VM */ - ProcConsumer xErr, /* Error log consumer callabck */ - void *pErrData /* Last argument to xErr() */ - ) -{ - jx9_gen_state *pGen = &pVm->sCodeGen; - GenBlock *pBlock, *pParent; - /* Point to the global scope */ - pBlock = pGen->pCurrent; - while( pBlock->pParent != 0 ){ - pParent = pBlock->pParent; - GenStateFreeBlock(pBlock); - pBlock = pParent; - } - pGen->xErr = xErr; - pGen->pErrData = pErrData; - pGen->pCurrent = &pGen->sGlobal; - pGen->pIn = pGen->pEnd = 0; - pGen->nErr = 0; - return SXRET_OK; -} -/* - * Generate a compile-time error message. - * If the error count limit is reached (usually 15 error message) - * this function return SXERR_ABORT.In that case upper-layers must - * abort compilation immediately. - */ -JX9_PRIVATE sxi32 jx9GenCompileError(jx9_gen_state *pGen,sxi32 nErrType,sxu32 nLine,const char *zFormat,...) -{ - SyBlob *pWorker = &pGen->pVm->pEngine->xConf.sErrConsumer; - const char *zErr = "Error"; - va_list ap; - if( nErrType == E_ERROR ){ - /* Increment the error counter */ - pGen->nErr++; - if( pGen->nErr > 15 ){ - /* Error count limit reached */ - SyBlobFormat(pWorker, "%u Error count limit reached, JX9 is aborting compilation\n", nLine); - /* Abort immediately */ - return SXERR_ABORT; - } - } - switch(nErrType){ - case E_WARNING: zErr = "Warning"; break; - case E_PARSE: zErr = "Parse error"; break; - case E_NOTICE: zErr = "Notice"; break; - default: - break; - } - /* Format the error message */ - SyBlobFormat(pWorker, "%u %s: ", nLine, zErr); - va_start(ap, zFormat); - SyBlobFormatAp(pWorker, zFormat, ap); - va_end(ap); - /* Append a new line */ - SyBlobAppend(pWorker, (const void *)"\n", sizeof(char)); - return JX9_OK; -} -/* - * ---------------------------------------------------------- - * File: jx9_const.c - * MD5: f3980b00dd1eda0bb2b749424a8dfffe - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: const.c v1.7 Win7 2012-12-13 00:01 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* This file implement built-in constants for the JX9 engine. */ -/* - * JX9_VERSION - * __JX9__ - * Expand the current version of the JX9 engine. - */ -static void JX9_VER_Const(jx9_value *pVal, void *pUnused) -{ - SXUNUSED(pUnused); - jx9_value_string(pVal, jx9_lib_signature(), -1/*Compute length automatically*/); -} -#ifdef __WINNT__ -#include -#elif defined(__UNIXES__) -#include -#endif -/* - * JX9_OS - * __OS__ - * Expand the name of the host Operating System. - */ -static void JX9_OS_Const(jx9_value *pVal, void *pUnused) -{ -#if defined(__WINNT__) - jx9_value_string(pVal, "WinNT", (int)sizeof("WinNT")-1); -#elif defined(__UNIXES__) - struct utsname sInfo; - if( uname(&sInfo) != 0 ){ - jx9_value_string(pVal, "Unix", (int)sizeof("Unix")-1); - }else{ - jx9_value_string(pVal, sInfo.sysname, -1); - } -#else - jx9_value_string(pVal,"Host OS", (int)sizeof("Host OS")-1); -#endif - SXUNUSED(pUnused); -} -/* - * JX9_EOL - * Expand the correct 'End Of Line' symbol for this platform. - */ -static void JX9_EOL_Const(jx9_value *pVal, void *pUnused) -{ - SXUNUSED(pUnused); -#ifdef __WINNT__ - jx9_value_string(pVal, "\r\n", (int)sizeof("\r\n")-1); -#else - jx9_value_string(pVal, "\n", (int)sizeof(char)); -#endif -} -/* - * JX9_INT_MAX - * Expand the largest integer supported. - * Note that JX9 deals with 64-bit integer for all platforms. - */ -static void JX9_INTMAX_Const(jx9_value *pVal, void *pUnused) -{ - SXUNUSED(pUnused); - jx9_value_int64(pVal, SXI64_HIGH); -} -/* - * JX9_INT_SIZE - * Expand the size in bytes of a 64-bit integer. - */ -static void JX9_INTSIZE_Const(jx9_value *pVal, void *pUnused) -{ - SXUNUSED(pUnused); - jx9_value_int64(pVal, sizeof(sxi64)); -} -/* - * DIRECTORY_SEPARATOR. - * Expand the directory separator character. - */ -static void JX9_DIRSEP_Const(jx9_value *pVal, void *pUnused) -{ - SXUNUSED(pUnused); -#ifdef __WINNT__ - jx9_value_string(pVal, "\\", (int)sizeof(char)); -#else - jx9_value_string(pVal, "/", (int)sizeof(char)); -#endif -} -/* - * PATH_SEPARATOR. - * Expand the path separator character. - */ -static void JX9_PATHSEP_Const(jx9_value *pVal, void *pUnused) -{ - SXUNUSED(pUnused); -#ifdef __WINNT__ - jx9_value_string(pVal, ";", (int)sizeof(char)); -#else - jx9_value_string(pVal, ":", (int)sizeof(char)); -#endif -} -#ifndef __WINNT__ -#include -#endif -/* - * __TIME__ - * Expand the current time (GMT). - */ -static void JX9_TIME_Const(jx9_value *pVal, void *pUnused) -{ - Sytm sTm; -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = gmtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - SXUNUSED(pUnused); /* cc warning */ - /* Expand */ - jx9_value_string_format(pVal, "%02d:%02d:%02d", sTm.tm_hour, sTm.tm_min, sTm.tm_sec); -} -/* - * __DATE__ - * Expand the current date in the ISO-8601 format. - */ -static void JX9_DATE_Const(jx9_value *pVal, void *pUnused) -{ - Sytm sTm; -#ifdef __WINNT__ - SYSTEMTIME sOS; - GetSystemTime(&sOS); - SYSTEMTIME_TO_SYTM(&sOS, &sTm); -#else - struct tm *pTm; - time_t t; - time(&t); - pTm = gmtime(&t); - STRUCT_TM_TO_SYTM(pTm, &sTm); -#endif - SXUNUSED(pUnused); /* cc warning */ - /* Expand */ - jx9_value_string_format(pVal, "%04d-%02d-%02d", sTm.tm_year, sTm.tm_mon+1, sTm.tm_mday); -} -/* - * __FILE__ - * Path of the processed script. - */ -static void JX9_FILE_Const(jx9_value *pVal, void *pUserData) -{ - jx9_vm *pVm = (jx9_vm *)pUserData; - SyString *pFile; - /* Peek the top entry */ - pFile = (SyString *)SySetPeek(&pVm->aFiles); - if( pFile == 0 ){ - /* Expand the magic word: ":MEMORY:" */ - jx9_value_string(pVal, ":MEMORY:", (int)sizeof(":MEMORY:")-1); - }else{ - jx9_value_string(pVal, pFile->zString, pFile->nByte); - } -} -/* - * __DIR__ - * Directory holding the processed script. - */ -static void JX9_DIR_Const(jx9_value *pVal, void *pUserData) -{ - jx9_vm *pVm = (jx9_vm *)pUserData; - SyString *pFile; - /* Peek the top entry */ - pFile = (SyString *)SySetPeek(&pVm->aFiles); - if( pFile == 0 ){ - /* Expand the magic word: ":MEMORY:" */ - jx9_value_string(pVal, ":MEMORY:", (int)sizeof(":MEMORY:")-1); - }else{ - if( pFile->nByte > 0 ){ - const char *zDir; - int nLen; - zDir = jx9ExtractDirName(pFile->zString, (int)pFile->nByte, &nLen); - jx9_value_string(pVal, zDir, nLen); - }else{ - /* Expand '.' as the current directory*/ - jx9_value_string(pVal, ".", (int)sizeof(char)); - } - } -} -/* - * E_ERROR - * Expands 1 - */ -static void JX9_E_ERROR_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 1); - SXUNUSED(pUserData); -} -/* - * E_WARNING - * Expands 2 - */ -static void JX9_E_WARNING_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 2); - SXUNUSED(pUserData); -} -/* - * E_PARSE - * Expands 4 - */ -static void JX9_E_PARSE_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 4); - SXUNUSED(pUserData); -} -/* - * E_NOTICE - * Expands 8 - */ -static void JX9_E_NOTICE_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 8); - SXUNUSED(pUserData); -} -/* - * CASE_LOWER - * Expands 0. - */ -static void JX9_CASE_LOWER_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 0); - SXUNUSED(pUserData); -} -/* - * CASE_UPPER - * Expands 1. - */ -static void JX9_CASE_UPPER_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 1); - SXUNUSED(pUserData); -} -/* - * STR_PAD_LEFT - * Expands 0. - */ -static void JX9_STR_PAD_LEFT_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 0); - SXUNUSED(pUserData); -} -/* - * STR_PAD_RIGHT - * Expands 1. - */ -static void JX9_STR_PAD_RIGHT_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 1); - SXUNUSED(pUserData); -} -/* - * STR_PAD_BOTH - * Expands 2. - */ -static void JX9_STR_PAD_BOTH_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 2); - SXUNUSED(pUserData); -} -/* - * COUNT_NORMAL - * Expands 0 - */ -static void JX9_COUNT_NORMAL_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 0); - SXUNUSED(pUserData); -} -/* - * COUNT_RECURSIVE - * Expands 1. - */ -static void JX9_COUNT_RECURSIVE_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 1); - SXUNUSED(pUserData); -} -/* - * SORT_ASC - * Expands 1. - */ -static void JX9_SORT_ASC_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 1); - SXUNUSED(pUserData); -} -/* - * SORT_DESC - * Expands 2. - */ -static void JX9_SORT_DESC_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 2); - SXUNUSED(pUserData); -} -/* - * SORT_REGULAR - * Expands 3. - */ -static void JX9_SORT_REG_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 3); - SXUNUSED(pUserData); -} -/* - * SORT_NUMERIC - * Expands 4. - */ -static void JX9_SORT_NUMERIC_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 4); - SXUNUSED(pUserData); -} -/* - * SORT_STRING - * Expands 5. - */ -static void JX9_SORT_STRING_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 5); - SXUNUSED(pUserData); -} -/* - * JX9_ROUND_HALF_UP - * Expands 1. - */ -static void JX9_JX9_ROUND_HALF_UP_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 1); - SXUNUSED(pUserData); -} -/* - * SJX9_ROUND_HALF_DOWN - * Expands 2. - */ -static void JX9_JX9_ROUND_HALF_DOWN_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 2); - SXUNUSED(pUserData); -} -/* - * JX9_ROUND_HALF_EVEN - * Expands 3. - */ -static void JX9_JX9_ROUND_HALF_EVEN_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 3); - SXUNUSED(pUserData); -} -/* - * JX9_ROUND_HALF_ODD - * Expands 4. - */ -static void JX9_JX9_ROUND_HALF_ODD_Const(jx9_value *pVal, void *pUserData) -{ - jx9_value_int(pVal, 4); - SXUNUSED(pUserData); -} -#ifdef JX9_ENABLE_MATH_FUNC -/* - * PI - * Expand the value of pi. - */ -static void JX9_M_PI_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, JX9_PI); -} -/* - * M_E - * Expand 2.7182818284590452354 - */ -static void JX9_M_E_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 2.7182818284590452354); -} -/* - * M_LOG2E - * Expand 2.7182818284590452354 - */ -static void JX9_M_LOG2E_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 1.4426950408889634074); -} -/* - * M_LOG10E - * Expand 0.4342944819032518276 - */ -static void JX9_M_LOG10E_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 0.4342944819032518276); -} -/* - * M_LN2 - * Expand 0.69314718055994530942 - */ -static void JX9_M_LN2_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 0.69314718055994530942); -} -/* - * M_LN10 - * Expand 2.30258509299404568402 - */ -static void JX9_M_LN10_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 2.30258509299404568402); -} -/* - * M_PI_2 - * Expand 1.57079632679489661923 - */ -static void JX9_M_PI_2_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 1.57079632679489661923); -} -/* - * M_PI_4 - * Expand 0.78539816339744830962 - */ -static void JX9_M_PI_4_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 0.78539816339744830962); -} -/* - * M_1_PI - * Expand 0.31830988618379067154 - */ -static void JX9_M_1_PI_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 0.31830988618379067154); -} -/* - * M_2_PI - * Expand 0.63661977236758134308 - */ -static void JX9_M_2_PI_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 0.63661977236758134308); -} -/* - * M_SQRTPI - * Expand 1.77245385090551602729 - */ -static void JX9_M_SQRTPI_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 1.77245385090551602729); -} -/* - * M_2_SQRTPI - * Expand 1.12837916709551257390 - */ -static void JX9_M_2_SQRTPI_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 1.12837916709551257390); -} -/* - * M_SQRT2 - * Expand 1.41421356237309504880 - */ -static void JX9_M_SQRT2_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 1.41421356237309504880); -} -/* - * M_SQRT3 - * Expand 1.73205080756887729352 - */ -static void JX9_M_SQRT3_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 1.73205080756887729352); -} -/* - * M_SQRT1_2 - * Expand 0.70710678118654752440 - */ -static void JX9_M_SQRT1_2_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 0.70710678118654752440); -} -/* - * M_LNPI - * Expand 1.14472988584940017414 - */ -static void JX9_M_LNPI_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 1.14472988584940017414); -} -/* - * M_EULER - * Expand 0.57721566490153286061 - */ -static void JX9_M_EULER_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_double(pVal, 0.57721566490153286061); -} -#endif /* JX9_DISABLE_BUILTIN_MATH */ -/* - * DATE_ATOM - * Expand Atom (example: 2005-08-15T15:52:01+00:00) - */ -static void JX9_DATE_ATOM_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "Y-m-d\\TH:i:sP", -1/*Compute length automatically*/); -} -/* - * DATE_COOKIE - * HTTP Cookies (example: Monday, 15-Aug-05 15:52:01 UTC) - */ -static void JX9_DATE_COOKIE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "l, d-M-y H:i:s T", -1/*Compute length automatically*/); -} -/* - * DATE_ISO8601 - * ISO-8601 (example: 2005-08-15T15:52:01+0000) - */ -static void JX9_DATE_ISO8601_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "Y-m-d\\TH:i:sO", -1/*Compute length automatically*/); -} -/* - * DATE_RFC822 - * RFC 822 (example: Mon, 15 Aug 05 15:52:01 +0000) - */ -static void JX9_DATE_RFC822_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "D, d M y H:i:s O", -1/*Compute length automatically*/); -} -/* - * DATE_RFC850 - * RFC 850 (example: Monday, 15-Aug-05 15:52:01 UTC) - */ -static void JX9_DATE_RFC850_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "l, d-M-y H:i:s T", -1/*Compute length automatically*/); -} -/* - * DATE_RFC1036 - * RFC 1123 (example: Mon, 15 Aug 2005 15:52:01 +0000) - */ -static void JX9_DATE_RFC1036_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "D, d M y H:i:s O", -1/*Compute length automatically*/); -} -/* - * DATE_RFC1123 - * RFC 1123 (example: Mon, 15 Aug 2005 15:52:01 +0000) - */ -static void JX9_DATE_RFC1123_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "D, d M Y H:i:s O", -1/*Compute length automatically*/); -} -/* - * DATE_RFC2822 - * RFC 2822 (Mon, 15 Aug 2005 15:52:01 +0000) - */ -static void JX9_DATE_RFC2822_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "D, d M Y H:i:s O", -1/*Compute length automatically*/); -} -/* - * DATE_RSS - * RSS (Mon, 15 Aug 2005 15:52:01 +0000) - */ -static void JX9_DATE_RSS_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "D, d M Y H:i:s O", -1/*Compute length automatically*/); -} -/* - * DATE_W3C - * World Wide Web Consortium (example: 2005-08-15T15:52:01+00:00) - */ -static void JX9_DATE_W3C_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_string(pVal, "Y-m-d\\TH:i:sP", -1/*Compute length automatically*/); -} -/* - * ENT_COMPAT - * Expand 0x01 (Must be a power of two) - */ -static void JX9_ENT_COMPAT_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x01); -} -/* - * ENT_QUOTES - * Expand 0x02 (Must be a power of two) - */ -static void JX9_ENT_QUOTES_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x02); -} -/* - * ENT_NOQUOTES - * Expand 0x04 (Must be a power of two) - */ -static void JX9_ENT_NOQUOTES_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x04); -} -/* - * ENT_IGNORE - * Expand 0x08 (Must be a power of two) - */ -static void JX9_ENT_IGNORE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x08); -} -/* - * ENT_SUBSTITUTE - * Expand 0x10 (Must be a power of two) - */ -static void JX9_ENT_SUBSTITUTE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x10); -} -/* - * ENT_DISALLOWED - * Expand 0x20 (Must be a power of two) - */ -static void JX9_ENT_DISALLOWED_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x20); -} -/* - * ENT_HTML401 - * Expand 0x40 (Must be a power of two) - */ -static void JX9_ENT_HTML401_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x40); -} -/* - * ENT_XML1 - * Expand 0x80 (Must be a power of two) - */ -static void JX9_ENT_XML1_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x80); -} -/* - * ENT_XHTML - * Expand 0x100 (Must be a power of two) - */ -static void JX9_ENT_XHTML_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x100); -} -/* - * ENT_HTML5 - * Expand 0x200 (Must be a power of two) - */ -static void JX9_ENT_HTML5_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x200); -} -/* - * ISO-8859-1 - * ISO_8859_1 - * Expand 1 - */ -static void JX9_ISO88591_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * UTF-8 - * UTF8 - * Expand 2 - */ -static void JX9_UTF8_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * HTML_ENTITIES - * Expand 1 - */ -static void JX9_HTML_ENTITIES_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * HTML_SPECIALCHARS - * Expand 2 - */ -static void JX9_HTML_SPECIALCHARS_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 2); -} -/* - * JX9_URL_SCHEME. - * Expand 1 - */ -static void JX9_JX9_URL_SCHEME_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * JX9_URL_HOST. - * Expand 2 - */ -static void JX9_JX9_URL_HOST_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 2); -} -/* - * JX9_URL_PORT. - * Expand 3 - */ -static void JX9_JX9_URL_PORT_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 3); -} -/* - * JX9_URL_USER. - * Expand 4 - */ -static void JX9_JX9_URL_USER_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 4); -} -/* - * JX9_URL_PASS. - * Expand 5 - */ -static void JX9_JX9_URL_PASS_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 5); -} -/* - * JX9_URL_PATH. - * Expand 6 - */ -static void JX9_JX9_URL_PATH_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 6); -} -/* - * JX9_URL_QUERY. - * Expand 7 - */ -static void JX9_JX9_URL_QUERY_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 7); -} -/* - * JX9_URL_FRAGMENT. - * Expand 8 - */ -static void JX9_JX9_URL_FRAGMENT_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 8); -} -/* - * JX9_QUERY_RFC1738 - * Expand 1 - */ -static void JX9_JX9_QUERY_RFC1738_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * JX9_QUERY_RFC3986 - * Expand 1 - */ -static void JX9_JX9_QUERY_RFC3986_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 2); -} -/* - * FNM_NOESCAPE - * Expand 0x01 (Must be a power of two) - */ -static void JX9_FNM_NOESCAPE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x01); -} -/* - * FNM_PATHNAME - * Expand 0x02 (Must be a power of two) - */ -static void JX9_FNM_PATHNAME_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x02); -} -/* - * FNM_PERIOD - * Expand 0x04 (Must be a power of two) - */ -static void JX9_FNM_PERIOD_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x04); -} -/* - * FNM_CASEFOLD - * Expand 0x08 (Must be a power of two) - */ -static void JX9_FNM_CASEFOLD_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x08); -} -/* - * PATHINFO_DIRNAME - * Expand 1. - */ -static void JX9_PATHINFO_DIRNAME_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * PATHINFO_BASENAME - * Expand 2. - */ -static void JX9_PATHINFO_BASENAME_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 2); -} -/* - * PATHINFO_EXTENSION - * Expand 3. - */ -static void JX9_PATHINFO_EXTENSION_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 3); -} -/* - * PATHINFO_FILENAME - * Expand 4. - */ -static void JX9_PATHINFO_FILENAME_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 4); -} -/* - * ASSERT_ACTIVE. - * Expand the value of JX9_ASSERT_ACTIVE defined in jx9Int.h - */ -static void JX9_ASSERT_ACTIVE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, JX9_ASSERT_DISABLE); -} -/* - * ASSERT_WARNING. - * Expand the value of JX9_ASSERT_WARNING defined in jx9Int.h - */ -static void JX9_ASSERT_WARNING_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, JX9_ASSERT_WARNING); -} -/* - * ASSERT_BAIL. - * Expand the value of JX9_ASSERT_BAIL defined in jx9Int.h - */ -static void JX9_ASSERT_BAIL_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, JX9_ASSERT_BAIL); -} -/* - * ASSERT_QUIET_EVAL. - * Expand the value of JX9_ASSERT_QUIET_EVAL defined in jx9Int.h - */ -static void JX9_ASSERT_QUIET_EVAL_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, JX9_ASSERT_QUIET_EVAL); -} -/* - * ASSERT_CALLBACK. - * Expand the value of JX9_ASSERT_CALLBACK defined in jx9Int.h - */ -static void JX9_ASSERT_CALLBACK_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, JX9_ASSERT_CALLBACK); -} -/* - * SEEK_SET. - * Expand 0 - */ -static void JX9_SEEK_SET_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0); -} -/* - * SEEK_CUR. - * Expand 1 - */ -static void JX9_SEEK_CUR_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * SEEK_END. - * Expand 2 - */ -static void JX9_SEEK_END_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 2); -} -/* - * LOCK_SH. - * Expand 2 - */ -static void JX9_LOCK_SH_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * LOCK_NB. - * Expand 5 - */ -static void JX9_LOCK_NB_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 5); -} -/* - * LOCK_EX. - * Expand 0x01 (MUST BE A POWER OF TWO) - */ -static void JX9_LOCK_EX_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x01); -} -/* - * LOCK_UN. - * Expand 0 - */ -static void JX9_LOCK_UN_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0); -} -/* - * FILE_USE_INC_PATH - * Expand 0x01 (Must be a power of two) - */ -static void JX9_FILE_USE_INCLUDE_PATH_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x1); -} -/* - * FILE_IGN_NL - * Expand 0x02 (Must be a power of two) - */ -static void JX9_FILE_IGNORE_NEW_LINES_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x2); -} -/* - * FILE_SKIP_EL - * Expand 0x04 (Must be a power of two) - */ -static void JX9_FILE_SKIP_EMPTY_LINES_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x4); -} -/* - * FILE_APPEND - * Expand 0x08 (Must be a power of two) - */ -static void JX9_FILE_APPEND_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x08); -} -/* - * SCANDIR_SORT_ASCENDING - * Expand 0 - */ -static void JX9_SCANDIR_SORT_ASCENDING_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0); -} -/* - * SCANDIR_SORT_DESCENDING - * Expand 1 - */ -static void JX9_SCANDIR_SORT_DESCENDING_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * SCANDIR_SORT_NONE - * Expand 2 - */ -static void JX9_SCANDIR_SORT_NONE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 2); -} -/* - * GLOB_MARK - * Expand 0x01 (must be a power of two) - */ -static void JX9_GLOB_MARK_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x01); -} -/* - * GLOB_NOSORT - * Expand 0x02 (must be a power of two) - */ -static void JX9_GLOB_NOSORT_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x02); -} -/* - * GLOB_NOCHECK - * Expand 0x04 (must be a power of two) - */ -static void JX9_GLOB_NOCHECK_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x04); -} -/* - * GLOB_NOESCAPE - * Expand 0x08 (must be a power of two) - */ -static void JX9_GLOB_NOESCAPE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x08); -} -/* - * GLOB_BRACE - * Expand 0x10 (must be a power of two) - */ -static void JX9_GLOB_BRACE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x10); -} -/* - * GLOB_ONLYDIR - * Expand 0x20 (must be a power of two) - */ -static void JX9_GLOB_ONLYDIR_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x20); -} -/* - * GLOB_ERR - * Expand 0x40 (must be a power of two) - */ -static void JX9_GLOB_ERR_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x40); -} -/* - * STDIN - * Expand the STDIN handle as a resource. - */ -static void JX9_STDIN_Const(jx9_value *pVal, void *pUserData) -{ - jx9_vm *pVm = (jx9_vm *)pUserData; - void *pResource; - pResource = jx9ExportStdin(pVm); - jx9_value_resource(pVal, pResource); -} -/* - * STDOUT - * Expand the STDOUT handle as a resource. - */ -static void JX9_STDOUT_Const(jx9_value *pVal, void *pUserData) -{ - jx9_vm *pVm = (jx9_vm *)pUserData; - void *pResource; - pResource = jx9ExportStdout(pVm); - jx9_value_resource(pVal, pResource); -} -/* - * STDERR - * Expand the STDERR handle as a resource. - */ -static void JX9_STDERR_Const(jx9_value *pVal, void *pUserData) -{ - jx9_vm *pVm = (jx9_vm *)pUserData; - void *pResource; - pResource = jx9ExportStderr(pVm); - jx9_value_resource(pVal, pResource); -} -/* - * INI_SCANNER_NORMAL - * Expand 1 - */ -static void JX9_INI_SCANNER_NORMAL_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 1); -} -/* - * INI_SCANNER_RAW - * Expand 2 - */ -static void JX9_INI_SCANNER_RAW_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 2); -} -/* - * EXTR_OVERWRITE - * Expand 0x01 (Must be a power of two) - */ -static void JX9_EXTR_OVERWRITE_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x1); -} -/* - * EXTR_SKIP - * Expand 0x02 (Must be a power of two) - */ -static void JX9_EXTR_SKIP_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x2); -} -/* - * EXTR_PREFIX_SAME - * Expand 0x04 (Must be a power of two) - */ -static void JX9_EXTR_PREFIX_SAME_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x4); -} -/* - * EXTR_PREFIX_ALL - * Expand 0x08 (Must be a power of two) - */ -static void JX9_EXTR_PREFIX_ALL_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x8); -} -/* - * EXTR_PREFIX_INVALID - * Expand 0x10 (Must be a power of two) - */ -static void JX9_EXTR_PREFIX_INVALID_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x10); -} -/* - * EXTR_IF_EXISTS - * Expand 0x20 (Must be a power of two) - */ -static void JX9_EXTR_IF_EXISTS_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x20); -} -/* - * EXTR_PREFIX_IF_EXISTS - * Expand 0x40 (Must be a power of two) - */ -static void JX9_EXTR_PREFIX_IF_EXISTS_Const(jx9_value *pVal, void *pUserData) -{ - SXUNUSED(pUserData); /* cc warning */ - jx9_value_int(pVal, 0x40); -} -/* - * Table of built-in constants. - */ -static const jx9_builtin_constant aBuiltIn[] = { - {"JX9_VERSION", JX9_VER_Const }, - {"JX9_ENGINE", JX9_VER_Const }, - {"__JX9__", JX9_VER_Const }, - {"JX9_OS", JX9_OS_Const }, - {"__OS__", JX9_OS_Const }, - {"JX9_EOL", JX9_EOL_Const }, - {"JX9_INT_MAX", JX9_INTMAX_Const }, - {"MAXINT", JX9_INTMAX_Const }, - {"JX9_INT_SIZE", JX9_INTSIZE_Const }, - {"PATH_SEPARATOR", JX9_PATHSEP_Const }, - {"DIRECTORY_SEPARATOR", JX9_DIRSEP_Const }, - {"DIR_SEP", JX9_DIRSEP_Const }, - {"__TIME__", JX9_TIME_Const }, - {"__DATE__", JX9_DATE_Const }, - {"__FILE__", JX9_FILE_Const }, - {"__DIR__", JX9_DIR_Const }, - {"E_ERROR", JX9_E_ERROR_Const }, - {"E_WARNING", JX9_E_WARNING_Const}, - {"E_PARSE", JX9_E_PARSE_Const }, - {"E_NOTICE", JX9_E_NOTICE_Const }, - {"CASE_LOWER", JX9_CASE_LOWER_Const }, - {"CASE_UPPER", JX9_CASE_UPPER_Const }, - {"STR_PAD_LEFT", JX9_STR_PAD_LEFT_Const }, - {"STR_PAD_RIGHT", JX9_STR_PAD_RIGHT_Const}, - {"STR_PAD_BOTH", JX9_STR_PAD_BOTH_Const }, - {"COUNT_NORMAL", JX9_COUNT_NORMAL_Const }, - {"COUNT_RECURSIVE", JX9_COUNT_RECURSIVE_Const }, - {"SORT_ASC", JX9_SORT_ASC_Const }, - {"SORT_DESC", JX9_SORT_DESC_Const }, - {"SORT_REGULAR", JX9_SORT_REG_Const }, - {"SORT_NUMERIC", JX9_SORT_NUMERIC_Const }, - {"SORT_STRING", JX9_SORT_STRING_Const }, - {"JX9_ROUND_HALF_DOWN", JX9_JX9_ROUND_HALF_DOWN_Const }, - {"JX9_ROUND_HALF_EVEN", JX9_JX9_ROUND_HALF_EVEN_Const }, - {"JX9_ROUND_HALF_UP", JX9_JX9_ROUND_HALF_UP_Const }, - {"JX9_ROUND_HALF_ODD", JX9_JX9_ROUND_HALF_ODD_Const }, -#ifdef JX9_ENABLE_MATH_FUNC - {"PI", JX9_M_PI_Const }, - {"M_E", JX9_M_E_Const }, - {"M_LOG2E", JX9_M_LOG2E_Const }, - {"M_LOG10E", JX9_M_LOG10E_Const }, - {"M_LN2", JX9_M_LN2_Const }, - {"M_LN10", JX9_M_LN10_Const }, - {"M_PI_2", JX9_M_PI_2_Const }, - {"M_PI_4", JX9_M_PI_4_Const }, - {"M_1_PI", JX9_M_1_PI_Const }, - {"M_2_PI", JX9_M_2_PI_Const }, - {"M_SQRTPI", JX9_M_SQRTPI_Const }, - {"M_2_SQRTPI", JX9_M_2_SQRTPI_Const }, - {"M_SQRT2", JX9_M_SQRT2_Const }, - {"M_SQRT3", JX9_M_SQRT3_Const }, - {"M_SQRT1_2", JX9_M_SQRT1_2_Const }, - {"M_LNPI", JX9_M_LNPI_Const }, - {"M_EULER", JX9_M_EULER_Const }, -#endif /* JX9_ENABLE_MATH_FUNC */ - {"DATE_ATOM", JX9_DATE_ATOM_Const }, - {"DATE_COOKIE", JX9_DATE_COOKIE_Const }, - {"DATE_ISO8601", JX9_DATE_ISO8601_Const }, - {"DATE_RFC822", JX9_DATE_RFC822_Const }, - {"DATE_RFC850", JX9_DATE_RFC850_Const }, - {"DATE_RFC1036", JX9_DATE_RFC1036_Const }, - {"DATE_RFC1123", JX9_DATE_RFC1123_Const }, - {"DATE_RFC2822", JX9_DATE_RFC2822_Const }, - {"DATE_RFC3339", JX9_DATE_ATOM_Const }, - {"DATE_RSS", JX9_DATE_RSS_Const }, - {"DATE_W3C", JX9_DATE_W3C_Const }, - {"ENT_COMPAT", JX9_ENT_COMPAT_Const }, - {"ENT_QUOTES", JX9_ENT_QUOTES_Const }, - {"ENT_NOQUOTES", JX9_ENT_NOQUOTES_Const }, - {"ENT_IGNORE", JX9_ENT_IGNORE_Const }, - {"ENT_SUBSTITUTE", JX9_ENT_SUBSTITUTE_Const}, - {"ENT_DISALLOWED", JX9_ENT_DISALLOWED_Const}, - {"ENT_HTML401", JX9_ENT_HTML401_Const }, - {"ENT_XML1", JX9_ENT_XML1_Const }, - {"ENT_XHTML", JX9_ENT_XHTML_Const }, - {"ENT_HTML5", JX9_ENT_HTML5_Const }, - {"ISO-8859-1", JX9_ISO88591_Const }, - {"ISO_8859_1", JX9_ISO88591_Const }, - {"UTF-8", JX9_UTF8_Const }, - {"UTF8", JX9_UTF8_Const }, - {"HTML_ENTITIES", JX9_HTML_ENTITIES_Const}, - {"HTML_SPECIALCHARS", JX9_HTML_SPECIALCHARS_Const }, - {"JX9_URL_SCHEME", JX9_JX9_URL_SCHEME_Const}, - {"JX9_URL_HOST", JX9_JX9_URL_HOST_Const}, - {"JX9_URL_PORT", JX9_JX9_URL_PORT_Const}, - {"JX9_URL_USER", JX9_JX9_URL_USER_Const}, - {"JX9_URL_PASS", JX9_JX9_URL_PASS_Const}, - {"JX9_URL_PATH", JX9_JX9_URL_PATH_Const}, - {"JX9_URL_QUERY", JX9_JX9_URL_QUERY_Const}, - {"JX9_URL_FRAGMENT", JX9_JX9_URL_FRAGMENT_Const}, - {"JX9_QUERY_RFC1738", JX9_JX9_QUERY_RFC1738_Const}, - {"JX9_QUERY_RFC3986", JX9_JX9_QUERY_RFC3986_Const}, - {"FNM_NOESCAPE", JX9_FNM_NOESCAPE_Const }, - {"FNM_PATHNAME", JX9_FNM_PATHNAME_Const }, - {"FNM_PERIOD", JX9_FNM_PERIOD_Const }, - {"FNM_CASEFOLD", JX9_FNM_CASEFOLD_Const }, - {"PATHINFO_DIRNAME", JX9_PATHINFO_DIRNAME_Const }, - {"PATHINFO_BASENAME", JX9_PATHINFO_BASENAME_Const }, - {"PATHINFO_EXTENSION", JX9_PATHINFO_EXTENSION_Const}, - {"PATHINFO_FILENAME", JX9_PATHINFO_FILENAME_Const }, - {"ASSERT_ACTIVE", JX9_ASSERT_ACTIVE_Const }, - {"ASSERT_WARNING", JX9_ASSERT_WARNING_Const }, - {"ASSERT_BAIL", JX9_ASSERT_BAIL_Const }, - {"ASSERT_QUIET_EVAL", JX9_ASSERT_QUIET_EVAL_Const }, - {"ASSERT_CALLBACK", JX9_ASSERT_CALLBACK_Const }, - {"SEEK_SET", JX9_SEEK_SET_Const }, - {"SEEK_CUR", JX9_SEEK_CUR_Const }, - {"SEEK_END", JX9_SEEK_END_Const }, - {"LOCK_EX", JX9_LOCK_EX_Const }, - {"LOCK_SH", JX9_LOCK_SH_Const }, - {"LOCK_NB", JX9_LOCK_NB_Const }, - {"LOCK_UN", JX9_LOCK_UN_Const }, - {"FILE_USE_INC_PATH", JX9_FILE_USE_INCLUDE_PATH_Const}, - {"FILE_IGN_NL", JX9_FILE_IGNORE_NEW_LINES_Const}, - {"FILE_SKIP_EL", JX9_FILE_SKIP_EMPTY_LINES_Const}, - {"FILE_APPEND", JX9_FILE_APPEND_Const }, - {"SCANDIR_SORT_ASC", JX9_SCANDIR_SORT_ASCENDING_Const }, - {"SCANDIR_SORT_DESC", JX9_SCANDIR_SORT_DESCENDING_Const }, - {"SCANDIR_SORT_NONE", JX9_SCANDIR_SORT_NONE_Const }, - {"GLOB_MARK", JX9_GLOB_MARK_Const }, - {"GLOB_NOSORT", JX9_GLOB_NOSORT_Const }, - {"GLOB_NOCHECK", JX9_GLOB_NOCHECK_Const }, - {"GLOB_NOESCAPE", JX9_GLOB_NOESCAPE_Const}, - {"GLOB_BRACE", JX9_GLOB_BRACE_Const }, - {"GLOB_ONLYDIR", JX9_GLOB_ONLYDIR_Const }, - {"GLOB_ERR", JX9_GLOB_ERR_Const }, - {"STDIN", JX9_STDIN_Const }, - {"stdin", JX9_STDIN_Const }, - {"STDOUT", JX9_STDOUT_Const }, - {"stdout", JX9_STDOUT_Const }, - {"STDERR", JX9_STDERR_Const }, - {"stderr", JX9_STDERR_Const }, - {"INI_SCANNER_NORMAL", JX9_INI_SCANNER_NORMAL_Const }, - {"INI_SCANNER_RAW", JX9_INI_SCANNER_RAW_Const }, - {"EXTR_OVERWRITE", JX9_EXTR_OVERWRITE_Const }, - {"EXTR_SKIP", JX9_EXTR_SKIP_Const }, - {"EXTR_PREFIX_SAME", JX9_EXTR_PREFIX_SAME_Const }, - {"EXTR_PREFIX_ALL", JX9_EXTR_PREFIX_ALL_Const }, - {"EXTR_PREFIX_INVALID", JX9_EXTR_PREFIX_INVALID_Const }, - {"EXTR_IF_EXISTS", JX9_EXTR_IF_EXISTS_Const }, - {"EXTR_PREFIX_IF_EXISTS", JX9_EXTR_PREFIX_IF_EXISTS_Const} -}; -/* - * Register the built-in constants defined above. - */ -JX9_PRIVATE void jx9RegisterBuiltInConstant(jx9_vm *pVm) -{ - sxu32 n; - /* - * Note that all built-in constants have access to the jx9 virtual machine - * that trigger the constant invocation as their private data. - */ - for( n = 0 ; n < SX_ARRAYSIZE(aBuiltIn) ; ++n ){ - jx9_create_constant(&(*pVm), aBuiltIn[n].zName, aBuiltIn[n].xExpand, &(*pVm)); - } -} -/* - * ---------------------------------------------------------- - * File: jx9_hashmap.c - * MD5: 4e93d15cd37e6093e25d8ede3064e210 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: hashmap.c v2.6 Win7 2012-12-11 00:50 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* This file implement generic hashmaps used to represent JSON arrays and objects */ -/* Allowed node types */ -#define HASHMAP_INT_NODE 1 /* Node with an int [i.e: 64-bit integer] key */ -#define HASHMAP_BLOB_NODE 2 /* Node with a string/BLOB key */ -/* - * Default hash function for int [i.e; 64-bit integer] keys. - */ -static sxu32 IntHash(sxi64 iKey) -{ - return (sxu32)(iKey ^ (iKey << 8) ^ (iKey >> 8)); -} -/* - * Default hash function for string/BLOB keys. - */ -static sxu32 BinHash(const void *pSrc, sxu32 nLen) -{ - register unsigned char *zIn = (unsigned char *)pSrc; - unsigned char *zEnd; - sxu32 nH = 5381; - zEnd = &zIn[nLen]; - for(;;){ - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - } - return nH; -} -/* - * Return the total number of entries in a given hashmap. - * If bRecurisve is set to TRUE then recurse on hashmap entries. - * If the nesting limit is reached, this function abort immediately. - */ -static sxi64 HashmapCount(jx9_hashmap *pMap, int bRecursive, int iRecCount) -{ - sxi64 iCount = 0; - if( !bRecursive ){ - iCount = pMap->nEntry; - }else{ - /* Recursive hashmap walk */ - jx9_hashmap_node *pEntry = pMap->pLast; - jx9_value *pElem; - sxu32 n = 0; - for(;;){ - if( n >= pMap->nEntry ){ - break; - } - /* Point to the element value */ - pElem = (jx9_value *)SySetAt(&pMap->pVm->aMemObj, pEntry->nValIdx); - if( pElem ){ - if( pElem->iFlags & MEMOBJ_HASHMAP ){ - if( iRecCount > 31 ){ - /* Nesting limit reached */ - return iCount; - } - /* Recurse */ - iRecCount++; - iCount += HashmapCount((jx9_hashmap *)pElem->x.pOther, TRUE, iRecCount); - iRecCount--; - } - } - /* Point to the next entry */ - pEntry = pEntry->pNext; - ++n; - } - /* Update count */ - iCount += pMap->nEntry; - } - return iCount; -} -/* - * Allocate a new hashmap node with a 64-bit integer key. - * If something goes wrong [i.e: out of memory], this function return NULL. - * Otherwise a fresh [jx9_hashmap_node] instance is returned. - */ -static jx9_hashmap_node * HashmapNewIntNode(jx9_hashmap *pMap, sxi64 iKey, sxu32 nHash, sxu32 nValIdx) -{ - jx9_hashmap_node *pNode; - /* Allocate a new node */ - pNode = (jx9_hashmap_node *)SyMemBackendPoolAlloc(&pMap->pVm->sAllocator, sizeof(jx9_hashmap_node)); - if( pNode == 0 ){ - return 0; - } - /* Zero the stucture */ - SyZero(pNode, sizeof(jx9_hashmap_node)); - /* Fill in the structure */ - pNode->pMap = &(*pMap); - pNode->iType = HASHMAP_INT_NODE; - pNode->nHash = nHash; - pNode->xKey.iKey = iKey; - pNode->nValIdx = nValIdx; - return pNode; -} -/* - * Allocate a new hashmap node with a BLOB key. - * If something goes wrong [i.e: out of memory], this function return NULL. - * Otherwise a fresh [jx9_hashmap_node] instance is returned. - */ -static jx9_hashmap_node * HashmapNewBlobNode(jx9_hashmap *pMap, const void *pKey, sxu32 nKeyLen, sxu32 nHash, sxu32 nValIdx) -{ - jx9_hashmap_node *pNode; - /* Allocate a new node */ - pNode = (jx9_hashmap_node *)SyMemBackendPoolAlloc(&pMap->pVm->sAllocator, sizeof(jx9_hashmap_node)); - if( pNode == 0 ){ - return 0; - } - /* Zero the stucture */ - SyZero(pNode, sizeof(jx9_hashmap_node)); - /* Fill in the structure */ - pNode->pMap = &(*pMap); - pNode->iType = HASHMAP_BLOB_NODE; - pNode->nHash = nHash; - SyBlobInit(&pNode->xKey.sKey, &pMap->pVm->sAllocator); - SyBlobAppend(&pNode->xKey.sKey, pKey, nKeyLen); - pNode->nValIdx = nValIdx; - return pNode; -} -/* - * link a hashmap node to the given bucket index (last argument to this function). - */ -static void HashmapNodeLink(jx9_hashmap *pMap, jx9_hashmap_node *pNode, sxu32 nBucketIdx) -{ - /* Link */ - if( pMap->apBucket[nBucketIdx] != 0 ){ - pNode->pNextCollide = pMap->apBucket[nBucketIdx]; - pMap->apBucket[nBucketIdx]->pPrevCollide = pNode; - } - pMap->apBucket[nBucketIdx] = pNode; - /* Link to the map list */ - if( pMap->pFirst == 0 ){ - pMap->pFirst = pMap->pLast = pNode; - /* Point to the first inserted node */ - pMap->pCur = pNode; - }else{ - MACRO_LD_PUSH(pMap->pLast, pNode); - } - ++pMap->nEntry; -} -/* - * Unlink a node from the hashmap. - * If the node count reaches zero then release the whole hash-bucket. - */ -static void jx9HashmapUnlinkNode(jx9_hashmap_node *pNode) -{ - jx9_hashmap *pMap = pNode->pMap; - jx9_vm *pVm = pMap->pVm; - /* Unlink from the corresponding bucket */ - if( pNode->pPrevCollide == 0 ){ - pMap->apBucket[pNode->nHash & (pMap->nSize - 1)] = pNode->pNextCollide; - }else{ - pNode->pPrevCollide->pNextCollide = pNode->pNextCollide; - } - if( pNode->pNextCollide ){ - pNode->pNextCollide->pPrevCollide = pNode->pPrevCollide; - } - if( pMap->pFirst == pNode ){ - pMap->pFirst = pNode->pPrev; - } - if( pMap->pCur == pNode ){ - /* Advance the node cursor */ - pMap->pCur = pMap->pCur->pPrev; /* Reverse link */ - } - /* Unlink from the map list */ - MACRO_LD_REMOVE(pMap->pLast, pNode); - /* Restore to the free list */ - jx9VmUnsetMemObj(pVm, pNode->nValIdx); - if( pNode->iType == HASHMAP_BLOB_NODE ){ - SyBlobRelease(&pNode->xKey.sKey); - } - SyMemBackendPoolFree(&pVm->sAllocator, pNode); - pMap->nEntry--; - if( pMap->nEntry < 1 ){ - /* Free the hash-bucket */ - SyMemBackendFree(&pVm->sAllocator, pMap->apBucket); - pMap->apBucket = 0; - pMap->nSize = 0; - pMap->pFirst = pMap->pLast = pMap->pCur = 0; - } -} -#define HASHMAP_FILL_FACTOR 3 -/* - * Grow the hash-table and rehash all entries. - */ -static sxi32 HashmapGrowBucket(jx9_hashmap *pMap) -{ - if( pMap->nEntry >= pMap->nSize * HASHMAP_FILL_FACTOR ){ - jx9_hashmap_node **apOld = pMap->apBucket; - jx9_hashmap_node *pEntry, **apNew; - sxu32 nNew = pMap->nSize << 1; - sxu32 nBucket; - sxu32 n; - if( nNew < 1 ){ - nNew = 16; - } - /* Allocate a new bucket */ - apNew = (jx9_hashmap_node **)SyMemBackendAlloc(&pMap->pVm->sAllocator, nNew * sizeof(jx9_hashmap_node *)); - if( apNew == 0 ){ - if( pMap->nSize < 1 ){ - return SXERR_MEM; /* Fatal */ - } - /* Not so fatal here, simply a performance hit */ - return SXRET_OK; - } - /* Zero the table */ - SyZero((void *)apNew, nNew * sizeof(jx9_hashmap_node *)); - /* Reflect the change */ - pMap->apBucket = apNew; - pMap->nSize = nNew; - if( apOld == 0 ){ - /* First allocated table [i.e: no entry], return immediately */ - return SXRET_OK; - } - /* Rehash old entries */ - pEntry = pMap->pFirst; - n = 0; - for( ;; ){ - if( n >= pMap->nEntry ){ - break; - } - /* Clear the old collision link */ - pEntry->pNextCollide = pEntry->pPrevCollide = 0; - /* Link to the new bucket */ - nBucket = pEntry->nHash & (nNew - 1); - if( pMap->apBucket[nBucket] != 0 ){ - pEntry->pNextCollide = pMap->apBucket[nBucket]; - pMap->apBucket[nBucket]->pPrevCollide = pEntry; - } - pMap->apBucket[nBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - n++; - } - /* Free the old table */ - SyMemBackendFree(&pMap->pVm->sAllocator, (void *)apOld); - } - return SXRET_OK; -} -/* - * Insert a 64-bit integer key and it's associated value (if any) in the given - * hashmap. - */ -static sxi32 HashmapInsertIntKey(jx9_hashmap *pMap,sxi64 iKey,jx9_value *pValue) -{ - jx9_hashmap_node *pNode; - jx9_value *pObj; - sxu32 nIdx; - sxu32 nHash; - sxi32 rc; - /* Reserve a jx9_value for the value */ - pObj = jx9VmReserveMemObj(pMap->pVm,&nIdx); - if( pObj == 0 ){ - return SXERR_MEM; - } - if( pValue ){ - /* Duplicate the value */ - jx9MemObjStore(pValue, pObj); - } - /* Hash the key */ - nHash = pMap->xIntHash(iKey); - /* Allocate a new int node */ - pNode = HashmapNewIntNode(&(*pMap), iKey, nHash, nIdx); - if( pNode == 0 ){ - return SXERR_MEM; - } - /* Make sure the bucket is big enough to hold the new entry */ - rc = HashmapGrowBucket(&(*pMap)); - if( rc != SXRET_OK ){ - SyMemBackendPoolFree(&pMap->pVm->sAllocator, pNode); - return rc; - } - /* Perform the insertion */ - HashmapNodeLink(&(*pMap), pNode, nHash & (pMap->nSize - 1)); - /* All done */ - return SXRET_OK; -} -/* - * Insert a BLOB key and it's associated value (if any) in the given - * hashmap. - */ -static sxi32 HashmapInsertBlobKey(jx9_hashmap *pMap,const void *pKey,sxu32 nKeyLen,jx9_value *pValue) -{ - jx9_hashmap_node *pNode; - jx9_value *pObj; - sxu32 nHash; - sxu32 nIdx; - sxi32 rc; - /* Reserve a jx9_value for the value */ - pObj = jx9VmReserveMemObj(pMap->pVm,&nIdx); - if( pObj == 0 ){ - return SXERR_MEM; - } - if( pValue ){ - /* Duplicate the value */ - jx9MemObjStore(pValue, pObj); - } - /* Hash the key */ - nHash = pMap->xBlobHash(pKey, nKeyLen); - /* Allocate a new blob node */ - pNode = HashmapNewBlobNode(&(*pMap), pKey, nKeyLen, nHash, nIdx); - if( pNode == 0 ){ - return SXERR_MEM; - } - /* Make sure the bucket is big enough to hold the new entry */ - rc = HashmapGrowBucket(&(*pMap)); - if( rc != SXRET_OK ){ - SyMemBackendPoolFree(&pMap->pVm->sAllocator, pNode); - return rc; - } - /* Perform the insertion */ - HashmapNodeLink(&(*pMap), pNode, nHash & (pMap->nSize - 1)); - /* All done */ - return SXRET_OK; -} -/* - * Check if a given 64-bit integer key exists in the given hashmap. - * Write a pointer to the target node on success. Otherwise - * SXERR_NOTFOUND is returned on failure. - */ -static sxi32 HashmapLookupIntKey( - jx9_hashmap *pMap, /* Target hashmap */ - sxi64 iKey, /* lookup key */ - jx9_hashmap_node **ppNode /* OUT: target node on success */ - ) -{ - jx9_hashmap_node *pNode; - sxu32 nHash; - if( pMap->nEntry < 1 ){ - /* Don't bother hashing, there is no entry anyway */ - return SXERR_NOTFOUND; - } - /* Hash the key first */ - nHash = pMap->xIntHash(iKey); - /* Point to the appropriate bucket */ - pNode = pMap->apBucket[nHash & (pMap->nSize - 1)]; - /* Perform the lookup */ - for(;;){ - if( pNode == 0 ){ - break; - } - if( pNode->iType == HASHMAP_INT_NODE - && pNode->nHash == nHash - && pNode->xKey.iKey == iKey ){ - /* Node found */ - if( ppNode ){ - *ppNode = pNode; - } - return SXRET_OK; - } - /* Follow the collision link */ - pNode = pNode->pNextCollide; - } - /* No such entry */ - return SXERR_NOTFOUND; -} -/* - * Check if a given BLOB key exists in the given hashmap. - * Write a pointer to the target node on success. Otherwise - * SXERR_NOTFOUND is returned on failure. - */ -static sxi32 HashmapLookupBlobKey( - jx9_hashmap *pMap, /* Target hashmap */ - const void *pKey, /* Lookup key */ - sxu32 nKeyLen, /* Key length in bytes */ - jx9_hashmap_node **ppNode /* OUT: target node on success */ - ) -{ - jx9_hashmap_node *pNode; - sxu32 nHash; - if( pMap->nEntry < 1 ){ - /* Don't bother hashing, there is no entry anyway */ - return SXERR_NOTFOUND; - } - /* Hash the key first */ - nHash = pMap->xBlobHash(pKey, nKeyLen); - /* Point to the appropriate bucket */ - pNode = pMap->apBucket[nHash & (pMap->nSize - 1)]; - /* Perform the lookup */ - for(;;){ - if( pNode == 0 ){ - break; - } - if( pNode->iType == HASHMAP_BLOB_NODE - && pNode->nHash == nHash - && SyBlobLength(&pNode->xKey.sKey) == nKeyLen - && SyMemcmp(SyBlobData(&pNode->xKey.sKey), pKey, nKeyLen) == 0 ){ - /* Node found */ - if( ppNode ){ - *ppNode = pNode; - } - return SXRET_OK; - } - /* Follow the collision link */ - pNode = pNode->pNextCollide; - } - /* No such entry */ - return SXERR_NOTFOUND; -} -/* - * Check if the given BLOB key looks like a decimal number. - * Retrurn TRUE on success.FALSE otherwise. - */ -static int HashmapIsIntKey(SyBlob *pKey) -{ - const char *zIn = (const char *)SyBlobData(pKey); - const char *zEnd = &zIn[SyBlobLength(pKey)]; - if( (int)(zEnd-zIn) > 1 && zIn[0] == '0' ){ - /* Octal not decimal number */ - return FALSE; - } - if( (zIn[0] == '-' || zIn[0] == '+') && &zIn[1] < zEnd ){ - zIn++; - } - for(;;){ - if( zIn >= zEnd ){ - return TRUE; - } - if( (unsigned char)zIn[0] >= 0xc0 /* UTF-8 stream */ || !SyisDigit(zIn[0]) ){ - break; - } - zIn++; - } - /* Key does not look like a decimal number */ - return FALSE; -} -/* - * Check if a given key exists in the given hashmap. - * Write a pointer to the target node on success. - * Otherwise SXERR_NOTFOUND is returned on failure. - */ -static sxi32 HashmapLookup( - jx9_hashmap *pMap, /* Target hashmap */ - jx9_value *pKey, /* Lookup key */ - jx9_hashmap_node **ppNode /* OUT: target node on success */ - ) -{ - jx9_hashmap_node *pNode = 0; /* cc -O6 warning */ - sxi32 rc; - if( pKey->iFlags & (MEMOBJ_STRING|MEMOBJ_HASHMAP|MEMOBJ_RES) ){ - if( (pKey->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(&(*pKey)); - } - if( SyBlobLength(&pKey->sBlob) > 0 ){ - /* Perform a blob lookup */ - rc = HashmapLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), SyBlobLength(&pKey->sBlob), &pNode); - goto result; - } - } - /* Perform an int lookup */ - if((pKey->iFlags & MEMOBJ_INT) == 0 ){ - /* Force an integer cast */ - jx9MemObjToInteger(pKey); - } - /* Perform an int lookup */ - rc = HashmapLookupIntKey(&(*pMap), pKey->x.iVal, &pNode); -result: - if( rc == SXRET_OK ){ - /* Node found */ - if( ppNode ){ - *ppNode = pNode; - } - return SXRET_OK; - } - /* No such entry */ - return SXERR_NOTFOUND; -} -/* - * Insert a given key and it's associated value (if any) in the given - * hashmap. - * If a node with the given key already exists in the database - * then this function overwrite the old value. - */ -static sxi32 HashmapInsert( - jx9_hashmap *pMap, /* Target hashmap */ - jx9_value *pKey, /* Lookup key */ - jx9_value *pVal /* Node value */ - ) -{ - jx9_hashmap_node *pNode = 0; - sxi32 rc = SXRET_OK; - if( pMap->nEntry < 1 && pKey && (pKey->iFlags & MEMOBJ_STRING) ){ - pMap->iFlags |= HASHMAP_JSON_OBJECT; - } - if( pKey && (pKey->iFlags & (MEMOBJ_STRING|MEMOBJ_HASHMAP|MEMOBJ_RES)) ){ - if( (pKey->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(&(*pKey)); - } - if( SyBlobLength(&pKey->sBlob) < 1 || HashmapIsIntKey(&pKey->sBlob) ){ - if(SyBlobLength(&pKey->sBlob) < 1){ - /* Automatic index assign */ - pKey = 0; - } - goto IntKey; - } - if( SXRET_OK == HashmapLookupBlobKey(&(*pMap), SyBlobData(&pKey->sBlob), - SyBlobLength(&pKey->sBlob), &pNode) ){ - /* Overwrite the old value */ - jx9_value *pElem; - pElem = (jx9_value *)SySetAt(&pMap->pVm->aMemObj, pNode->nValIdx); - if( pElem ){ - if( pVal ){ - jx9MemObjStore(pVal, pElem); - }else{ - /* Nullify the entry */ - jx9MemObjToNull(pElem); - } - } - return SXRET_OK; - } - /* Perform a blob-key insertion */ - rc = HashmapInsertBlobKey(&(*pMap),SyBlobData(&pKey->sBlob),SyBlobLength(&pKey->sBlob),&(*pVal)); - return rc; - } -IntKey: - if( pKey ){ - if((pKey->iFlags & MEMOBJ_INT) == 0 ){ - /* Force an integer cast */ - jx9MemObjToInteger(pKey); - } - if( SXRET_OK == HashmapLookupIntKey(&(*pMap), pKey->x.iVal, &pNode) ){ - /* Overwrite the old value */ - jx9_value *pElem; - pElem = (jx9_value *)SySetAt(&pMap->pVm->aMemObj, pNode->nValIdx); - if( pElem ){ - if( pVal ){ - jx9MemObjStore(pVal, pElem); - }else{ - /* Nullify the entry */ - jx9MemObjToNull(pElem); - } - } - return SXRET_OK; - } - /* Perform a 64-bit-int-key insertion */ - rc = HashmapInsertIntKey(&(*pMap), pKey->x.iVal, &(*pVal)); - if( rc == SXRET_OK ){ - if( pKey->x.iVal >= pMap->iNextIdx ){ - /* Increment the automatic index */ - pMap->iNextIdx = pKey->x.iVal + 1; - /* Make sure the automatic index is not reserved */ - while( SXRET_OK == HashmapLookupIntKey(&(*pMap), pMap->iNextIdx, 0) ){ - pMap->iNextIdx++; - } - } - } - }else{ - /* Assign an automatic index */ - rc = HashmapInsertIntKey(&(*pMap),pMap->iNextIdx,&(*pVal)); - if( rc == SXRET_OK ){ - ++pMap->iNextIdx; - } - } - /* Insertion result */ - return rc; -} -/* - * Extract node value. - */ -static jx9_value * HashmapExtractNodeValue(jx9_hashmap_node *pNode) -{ - /* Point to the desired object */ - jx9_value *pObj; - pObj = (jx9_value *)SySetAt(&pNode->pMap->pVm->aMemObj, pNode->nValIdx); - return pObj; -} -/* - * Insert a node in the given hashmap. - * If a node with the given key already exists in the database - * then this function overwrite the old value. - */ -static sxi32 HashmapInsertNode(jx9_hashmap *pMap, jx9_hashmap_node *pNode, int bPreserve) -{ - jx9_value *pObj; - sxi32 rc; - /* Extract the node value */ - pObj = HashmapExtractNodeValue(&(*pNode)); - if( pObj == 0 ){ - return SXERR_EMPTY; - } - /* Preserve key */ - if( pNode->iType == HASHMAP_INT_NODE){ - /* Int64 key */ - if( !bPreserve ){ - /* Assign an automatic index */ - rc = HashmapInsert(&(*pMap), 0, pObj); - }else{ - rc = HashmapInsertIntKey(&(*pMap), pNode->xKey.iKey, pObj); - } - }else{ - /* Blob key */ - rc = HashmapInsertBlobKey(&(*pMap), SyBlobData(&pNode->xKey.sKey), - SyBlobLength(&pNode->xKey.sKey), pObj); - } - return rc; -} -/* - * Compare two node values. - * Return 0 if the node values are equals, > 0 if pLeft is greater than pRight - * or < 0 if pRight is greater than pLeft. - * For a full description on jx9_values comparison, refer to the implementation - * of the [jx9MemObjCmp()] function defined in memobj.c or the official - * documenation. - */ -static sxi32 HashmapNodeCmp(jx9_hashmap_node *pLeft, jx9_hashmap_node *pRight, int bStrict) -{ - jx9_value sObj1, sObj2; - sxi32 rc; - if( pLeft == pRight ){ - /* - * Same node.Refer to the sort() implementation defined - * below for more information on this sceanario. - */ - return 0; - } - /* Do the comparison */ - jx9MemObjInit(pLeft->pMap->pVm, &sObj1); - jx9MemObjInit(pLeft->pMap->pVm, &sObj2); - jx9HashmapExtractNodeValue(pLeft, &sObj1, FALSE); - jx9HashmapExtractNodeValue(pRight, &sObj2, FALSE); - rc = jx9MemObjCmp(&sObj1, &sObj2, bStrict, 0); - jx9MemObjRelease(&sObj1); - jx9MemObjRelease(&sObj2); - return rc; -} -/* - * Rehash a node with a 64-bit integer key. - * Refer to [merge_sort(), array_shift()] implementations for more information. - */ -static void HashmapRehashIntNode(jx9_hashmap_node *pEntry) -{ - jx9_hashmap *pMap = pEntry->pMap; - sxu32 nBucket; - /* Remove old collision links */ - if( pEntry->pPrevCollide ){ - pEntry->pPrevCollide->pNextCollide = pEntry->pNextCollide; - }else{ - pMap->apBucket[pEntry->nHash & (pMap->nSize - 1)] = pEntry->pNextCollide; - } - if( pEntry->pNextCollide ){ - pEntry->pNextCollide->pPrevCollide = pEntry->pPrevCollide; - } - pEntry->pNextCollide = pEntry->pPrevCollide = 0; - /* Compute the new hash */ - pEntry->nHash = pMap->xIntHash(pMap->iNextIdx); - pEntry->xKey.iKey = pMap->iNextIdx; - nBucket = pEntry->nHash & (pMap->nSize - 1); - /* Link to the new bucket */ - pEntry->pNextCollide = pMap->apBucket[nBucket]; - if( pMap->apBucket[nBucket] ){ - pMap->apBucket[nBucket]->pPrevCollide = pEntry; - } - pEntry->pNextCollide = pMap->apBucket[nBucket]; - pMap->apBucket[nBucket] = pEntry; - /* Increment the automatic index */ - pMap->iNextIdx++; -} -/* - * Perform a linear search on a given hashmap. - * Write a pointer to the target node on success. - * Otherwise SXERR_NOTFOUND is returned on failure. - * Refer to [array_intersect(), array_diff(), in_array(), ...] implementations - * for more information. - */ -static int HashmapFindValue( - jx9_hashmap *pMap, /* Target hashmap */ - jx9_value *pNeedle, /* Lookup key */ - jx9_hashmap_node **ppNode, /* OUT: target node on success */ - int bStrict /* TRUE for strict comparison */ - ) -{ - jx9_hashmap_node *pEntry; - jx9_value sVal, *pVal; - jx9_value sNeedle; - sxi32 rc; - sxu32 n; - /* Perform a linear search since we cannot sort the hashmap based on values */ - pEntry = pMap->pFirst; - n = pMap->nEntry; - jx9MemObjInit(pMap->pVm, &sVal); - jx9MemObjInit(pMap->pVm, &sNeedle); - for(;;){ - if( n < 1 ){ - break; - } - /* Extract node value */ - pVal = HashmapExtractNodeValue(pEntry); - if( pVal ){ - if( (pVal->iFlags|pNeedle->iFlags) & MEMOBJ_NULL ){ - sxi32 iF1 = pVal->iFlags; - sxi32 iF2 = pNeedle->iFlags; - if( iF1 == iF2 ){ - /* NULL values are equals */ - if( ppNode ){ - *ppNode = pEntry; - } - return SXRET_OK; - } - }else{ - /* Duplicate value */ - jx9MemObjLoad(pVal, &sVal); - jx9MemObjLoad(pNeedle, &sNeedle); - rc = jx9MemObjCmp(&sNeedle, &sVal, bStrict, 0); - jx9MemObjRelease(&sVal); - jx9MemObjRelease(&sNeedle); - if( rc == 0 ){ - if( ppNode ){ - *ppNode = pEntry; - } - /* Match found*/ - return SXRET_OK; - } - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - n--; - } - /* No such entry */ - return SXERR_NOTFOUND; -} -/* - * Compare two hashmaps. - * Return 0 if the hashmaps are equals.Any other value indicates inequality. - * Note on array comparison operators. - * According to the JX9 language reference manual. - * Array Operators Example Name Result - * $a + $b Union Union of $a and $b. - * $a == $b Equality TRUE if $a and $b have the same key/value pairs. - * $a === $b Identity TRUE if $a and $b have the same key/value pairs in the same - * order and of the same types. - * $a != $b Inequality TRUE if $a is not equal to $b. - * $a <> $b Inequality TRUE if $a is not equal to $b. - * $a !== $b Non-identity TRUE if $a is not identical to $b. - * The + operator returns the right-hand array appended to the left-hand array; - * For keys that exist in both arrays, the elements from the left-hand array will be used - * and the matching elements from the right-hand array will be ignored. - * "apple", "b" => "banana"); - * $b = array("a" => "pear", "b" => "strawberry", "c" => "cherry"); - * $c = $a + $b; // Union of $a and $b - * print "Union of \$a and \$b: \n"; - * dump($c); - * $c = $b + $a; // Union of $b and $a - * print "Union of \$b and \$a: \n"; - * dump($c); - * ?> - * When executed, this script will print the following: - * Union of $a and $b: - * array(3) { - * ["a"]=> - * string(5) "apple" - * ["b"]=> - * string(6) "banana" - * ["c"]=> - * string(6) "cherry" - * } - * Union of $b and $a: - * array(3) { - * ["a"]=> - * string(4) "pear" - * ["b"]=> - * string(10) "strawberry" - * ["c"]=> - * string(6) "cherry" - * } - * Elements of arrays are equal for the comparison if they have the same key and value. - */ -JX9_PRIVATE sxi32 jx9HashmapCmp( - jx9_hashmap *pLeft, /* Left hashmap */ - jx9_hashmap *pRight, /* Right hashmap */ - int bStrict /* TRUE for strict comparison */ - ) -{ - jx9_hashmap_node *pLe, *pRe; - sxi32 rc; - sxu32 n; - if( pLeft == pRight ){ - /* Same hashmap instance. This can easily happen since hashmaps are passed by reference. - * Unlike the engine. - */ - return 0; - } - if( pLeft->nEntry != pRight->nEntry ){ - /* Must have the same number of entries */ - return pLeft->nEntry > pRight->nEntry ? 1 : -1; - } - /* Point to the first inserted entry of the left hashmap */ - pLe = pLeft->pFirst; - pRe = 0; /* cc warning */ - /* Perform the comparison */ - n = pLeft->nEntry; - for(;;){ - if( n < 1 ){ - break; - } - if( pLe->iType == HASHMAP_INT_NODE){ - /* Int key */ - rc = HashmapLookupIntKey(&(*pRight), pLe->xKey.iKey, &pRe); - }else{ - SyBlob *pKey = &pLe->xKey.sKey; - /* Blob key */ - rc = HashmapLookupBlobKey(&(*pRight), SyBlobData(pKey), SyBlobLength(pKey), &pRe); - } - if( rc != SXRET_OK ){ - /* No such entry in the right side */ - return 1; - } - rc = 0; - if( bStrict ){ - /* Make sure, the keys are of the same type */ - if( pLe->iType != pRe->iType ){ - rc = 1; - } - } - if( !rc ){ - /* Compare nodes */ - rc = HashmapNodeCmp(pLe, pRe, bStrict); - } - if( rc != 0 ){ - /* Nodes key/value differ */ - return rc; - } - /* Point to the next entry */ - pLe = pLe->pPrev; /* Reverse link */ - n--; - } - return 0; /* Hashmaps are equals */ -} -/* - * Merge two hashmaps. - * Note on the merge process - * According to the JX9 language reference manual. - * Merges the elements of two arrays together so that the values of one are appended - * to the end of the previous one. It returns the resulting array (pDest). - * If the input arrays have the same string keys, then the later value for that key - * will overwrite the previous one. If, however, the arrays contain numeric keys - * the later value will not overwrite the original value, but will be appended. - * Values in the input array with numeric keys will be renumbered with incrementing - * keys starting from zero in the result array. - */ -static sxi32 HashmapMerge(jx9_hashmap *pSrc, jx9_hashmap *pDest) -{ - jx9_hashmap_node *pEntry; - jx9_value sKey, *pVal; - sxi32 rc; - sxu32 n; - if( pSrc == pDest ){ - /* Same map. This can easily happen since hashmaps are passed by reference. - * Unlike the engine. - */ - return SXRET_OK; - } - /* Point to the first inserted entry in the source */ - pEntry = pSrc->pFirst; - /* Perform the merge */ - for( n = 0 ; n < pSrc->nEntry ; ++n ){ - /* Extract the node value */ - pVal = HashmapExtractNodeValue(pEntry); - if( pEntry->iType == HASHMAP_BLOB_NODE ){ - /* Blob key insertion */ - jx9MemObjInitFromString(pDest->pVm, &sKey, 0); - jx9MemObjStringAppend(&sKey, (const char *)SyBlobData(&pEntry->xKey.sKey), SyBlobLength(&pEntry->xKey.sKey)); - rc = jx9HashmapInsert(&(*pDest), &sKey, pVal); - jx9MemObjRelease(&sKey); - }else{ - rc = HashmapInsert(&(*pDest), 0/* Automatic index assign */, pVal); - } - if( rc != SXRET_OK ){ - return rc; - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - return SXRET_OK; -} -/* - * Duplicate the contents of a hashmap. Store the copy in pDest. - * Refer to the [array_pad(), array_copy(), ...] implementation for more information. - */ -JX9_PRIVATE sxi32 jx9HashmapDup(jx9_hashmap *pSrc, jx9_hashmap *pDest) -{ - jx9_hashmap_node *pEntry; - jx9_value sKey, *pVal; - sxi32 rc; - sxu32 n; - if( pSrc == pDest ){ - /* Same map. This can easily happen since hashmaps are passed by reference. - * Unlike the engine. - */ - return SXRET_OK; - } - /* Point to the first inserted entry in the source */ - pEntry = pSrc->pFirst; - /* Perform the duplication */ - for( n = 0 ; n < pSrc->nEntry ; ++n ){ - /* Extract the node value */ - pVal = HashmapExtractNodeValue(pEntry); - if( pEntry->iType == HASHMAP_BLOB_NODE ){ - /* Blob key insertion */ - jx9MemObjInitFromString(pDest->pVm, &sKey, 0); - jx9MemObjStringAppend(&sKey, (const char *)SyBlobData(&pEntry->xKey.sKey), SyBlobLength(&pEntry->xKey.sKey)); - rc = jx9HashmapInsert(&(*pDest), &sKey, pVal); - jx9MemObjRelease(&sKey); - }else{ - /* Int key insertion */ - rc = HashmapInsertIntKey(&(*pDest), pEntry->xKey.iKey, pVal); - } - if( rc != SXRET_OK ){ - return rc; - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - return SXRET_OK; -} -/* - * Perform the union of two hashmaps. - * This operation is performed only if the user uses the '+' operator - * with a variable holding an array as follows: - * "apple", "b" => "banana"); - * $b = array("a" => "pear", "b" => "strawberry", "c" => "cherry"); - * $c = $a + $b; // Union of $a and $b - * print "Union of \$a and \$b: \n"; - * dump($c); - * $c = $b + $a; // Union of $b and $a - * print "Union of \$b and \$a: \n"; - * dump($c); - * ?> - * When executed, this script will print the following: - * Union of $a and $b: - * array(3) { - * ["a"]=> - * string(5) "apple" - * ["b"]=> - * string(6) "banana" - * ["c"]=> - * string(6) "cherry" - * } - * Union of $b and $a: - * array(3) { - * ["a"]=> - * string(4) "pear" - * ["b"]=> - * string(10) "strawberry" - * ["c"]=> - * string(6) "cherry" - * } - * The + operator returns the right-hand array appended to the left-hand array; - * For keys that exist in both arrays, the elements from the left-hand array will be used - * and the matching elements from the right-hand array will be ignored. - */ -JX9_PRIVATE sxi32 jx9HashmapUnion(jx9_hashmap *pLeft, jx9_hashmap *pRight) -{ - jx9_hashmap_node *pEntry; - sxi32 rc = SXRET_OK; - jx9_value *pObj; - sxu32 n; - if( pLeft == pRight ){ - /* Same map. This can easily happen since hashmaps are passed by reference. - * Unlike the engine. - */ - return SXRET_OK; - } - /* Perform the union */ - pEntry = pRight->pFirst; - for(n = 0 ; n < pRight->nEntry ; ++n ){ - /* Make sure the given key does not exists in the left array */ - if( pEntry->iType == HASHMAP_BLOB_NODE ){ - /* BLOB key */ - if( SXRET_OK != - HashmapLookupBlobKey(&(*pLeft), SyBlobData(&pEntry->xKey.sKey), SyBlobLength(&pEntry->xKey.sKey), 0) ){ - pObj = HashmapExtractNodeValue(pEntry); - if( pObj ){ - /* Perform the insertion */ - rc = HashmapInsertBlobKey(&(*pLeft), SyBlobData(&pEntry->xKey.sKey), - SyBlobLength(&pEntry->xKey.sKey),pObj); - if( rc != SXRET_OK ){ - return rc; - } - } - } - }else{ - /* INT key */ - if( SXRET_OK != HashmapLookupIntKey(&(*pLeft), pEntry->xKey.iKey, 0) ){ - pObj = HashmapExtractNodeValue(pEntry); - if( pObj ){ - /* Perform the insertion */ - rc = HashmapInsertIntKey(&(*pLeft), pEntry->xKey.iKey, pObj); - if( rc != SXRET_OK ){ - return rc; - } - } - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - return SXRET_OK; -} -/* - * Allocate a new hashmap. - * Return a pointer to the freshly allocated hashmap on success.NULL otherwise. - */ -JX9_PRIVATE jx9_hashmap * jx9NewHashmap( - jx9_vm *pVm, /* VM that trigger the hashmap creation */ - sxu32 (*xIntHash)(sxi64), /* Hash function for int keys.NULL otherwise*/ - sxu32 (*xBlobHash)(const void *, sxu32) /* Hash function for BLOB keys.NULL otherwise */ - ) -{ - jx9_hashmap *pMap; - /* Allocate a new instance */ - pMap = (jx9_hashmap *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_hashmap)); - if( pMap == 0 ){ - return 0; - } - /* Zero the structure */ - SyZero(pMap, sizeof(jx9_hashmap)); - /* Fill in the structure */ - pMap->pVm = &(*pVm); - pMap->iRef = 1; - /* pMap->iFlags = 0; */ - /* Default hash functions */ - pMap->xIntHash = xIntHash ? xIntHash : IntHash; - pMap->xBlobHash = xBlobHash ? xBlobHash : BinHash; - return pMap; -} -/* - * Install superglobals in the given virtual machine. - * Note on superglobals. - * According to the JX9 language reference manual. - * Superglobals are built-in variables that are always available in all scopes. -* Description -* All predefined variables in JX9 are "superglobals", which means they -* are available in all scopes throughout a script. -* These variables are: -* $_SERVER -* $_GET -* $_POST -* $_FILES -* $_REQUEST -* $_ENV -*/ -JX9_PRIVATE sxi32 jx9HashmapLoadBuiltin(jx9_vm *pVm) -{ - static const char * azSuper[] = { - "_SERVER", /* $_SERVER */ - "_GET", /* $_GET */ - "_POST", /* $_POST */ - "_FILES", /* $_FILES */ - "_REQUEST", /* $_REQUEST */ - "_COOKIE", /* $_COOKIE */ - "_ENV", /* $_ENV */ - "_HEADER", /* $_HEADER */ - "argv" /* $argv */ - }; - SyString *pFile; - sxi32 rc; - sxu32 n; - /* Install globals variable now */ - for( n = 0 ; n < SX_ARRAYSIZE(azSuper) ; n++ ){ - jx9_value *pSuper; - /* Request an empty array */ - pSuper = jx9_new_array(&(*pVm)); - if( pSuper == 0 ){ - return SXERR_MEM; - } - /* Install */ - rc = jx9_vm_config(&(*pVm),JX9_VM_CONFIG_CREATE_VAR, azSuper[n]/* Super-global name*/, pSuper/* Super-global value */); - if( rc != SXRET_OK ){ - return rc; - } - /* Release the value now it have been installed */ - jx9_release_value(&(*pVm), pSuper); - } - /* Set some $_SERVER entries */ - pFile = (SyString *)SySetPeek(&pVm->aFiles); - /* - * 'SCRIPT_FILENAME' - * The absolute pathname of the currently executing script. - */ - jx9_vm_config(pVm, JX9_VM_CONFIG_SERVER_ATTR, - "SCRIPT_FILENAME", - pFile ? pFile->zString : ":Memory:", - pFile ? pFile->nByte : sizeof(":Memory:") - 1 - ); - /* All done, all global variables are installed now */ - return SXRET_OK; -} -/* - * Release a hashmap. - */ -JX9_PRIVATE sxi32 jx9HashmapRelease(jx9_hashmap *pMap, int FreeDS) -{ - jx9_hashmap_node *pEntry, *pNext; - jx9_vm *pVm = pMap->pVm; - sxu32 n; - /* Start the release process */ - n = 0; - pEntry = pMap->pFirst; - for(;;){ - if( n >= pMap->nEntry ){ - break; - } - pNext = pEntry->pPrev; /* Reverse link */ - /* Restore the jx9_value to the free list */ - jx9VmUnsetMemObj(pVm, pEntry->nValIdx); - /* Release the node */ - if( pEntry->iType == HASHMAP_BLOB_NODE ){ - SyBlobRelease(&pEntry->xKey.sKey); - } - SyMemBackendPoolFree(&pVm->sAllocator, pEntry); - /* Point to the next entry */ - pEntry = pNext; - n++; - } - if( pMap->nEntry > 0 ){ - /* Release the hash bucket */ - SyMemBackendFree(&pVm->sAllocator, pMap->apBucket); - } - if( FreeDS ){ - /* Free the whole instance */ - SyMemBackendPoolFree(&pVm->sAllocator, pMap); - }else{ - /* Keep the instance but reset it's fields */ - pMap->apBucket = 0; - pMap->iNextIdx = 0; - pMap->nEntry = pMap->nSize = 0; - pMap->pFirst = pMap->pLast = pMap->pCur = 0; - } - return SXRET_OK; -} -/* - * Decrement the reference count of a given hashmap. - * If the count reaches zero which mean no more variables - * are pointing to this hashmap, then release the whole instance. - */ -JX9_PRIVATE void jx9HashmapUnref(jx9_hashmap *pMap) -{ - pMap->iRef--; - if( pMap->iRef < 1 ){ - jx9HashmapRelease(pMap, TRUE); - } -} -/* - * Check if a given key exists in the given hashmap. - * Write a pointer to the target node on success. - * Otherwise SXERR_NOTFOUND is returned on failure. - */ -JX9_PRIVATE sxi32 jx9HashmapLookup( - jx9_hashmap *pMap, /* Target hashmap */ - jx9_value *pKey, /* Lookup key */ - jx9_hashmap_node **ppNode /* OUT: Target node on success */ - ) -{ - sxi32 rc; - if( pMap->nEntry < 1 ){ - /* TICKET 1433-25: Don't bother hashing, the hashmap is empty anyway. - */ - return SXERR_NOTFOUND; - } - rc = HashmapLookup(&(*pMap), &(*pKey), ppNode); - return rc; -} -/* - * Insert a given key and it's associated value (if any) in the given - * hashmap. - * If a node with the given key already exists in the database - * then this function overwrite the old value. - */ -JX9_PRIVATE sxi32 jx9HashmapInsert( - jx9_hashmap *pMap, /* Target hashmap */ - jx9_value *pKey, /* Lookup key */ - jx9_value *pVal /* Node value.NULL otherwise */ - ) -{ - sxi32 rc; - rc = HashmapInsert(&(*pMap), &(*pKey), &(*pVal)); - return rc; -} -/* - * Reset the node cursor of a given hashmap. - */ -JX9_PRIVATE void jx9HashmapResetLoopCursor(jx9_hashmap *pMap) -{ - /* Reset the loop cursor */ - pMap->pCur = pMap->pFirst; -} -/* - * Return a pointer to the node currently pointed by the node cursor. - * If the cursor reaches the end of the list, then this function - * return NULL. - * Note that the node cursor is automatically advanced by this function. - */ -JX9_PRIVATE jx9_hashmap_node * jx9HashmapGetNextEntry(jx9_hashmap *pMap) -{ - jx9_hashmap_node *pCur = pMap->pCur; - if( pCur == 0 ){ - /* End of the list, return null */ - return 0; - } - /* Advance the node cursor */ - pMap->pCur = pCur->pPrev; /* Reverse link */ - return pCur; -} -/* - * Extract a node value. - */ -JX9_PRIVATE jx9_value * jx9HashmapGetNodeValue(jx9_hashmap_node *pNode) -{ - jx9_value *pValue; - pValue = HashmapExtractNodeValue(pNode); - return pValue; -} -/* - * Extract a node value (Second). - */ -JX9_PRIVATE void jx9HashmapExtractNodeValue(jx9_hashmap_node *pNode, jx9_value *pValue, int bStore) -{ - jx9_value *pEntry = HashmapExtractNodeValue(pNode); - if( pEntry ){ - if( bStore ){ - jx9MemObjStore(pEntry, pValue); - }else{ - jx9MemObjLoad(pEntry, pValue); - } - }else{ - jx9MemObjRelease(pValue); - } -} -/* - * Extract a node key. - */ -JX9_PRIVATE void jx9HashmapExtractNodeKey(jx9_hashmap_node *pNode,jx9_value *pKey) -{ - /* Fill with the current key */ - if( pNode->iType == HASHMAP_INT_NODE ){ - if( SyBlobLength(&pKey->sBlob) > 0 ){ - SyBlobRelease(&pKey->sBlob); - } - pKey->x.iVal = pNode->xKey.iKey; - MemObjSetType(pKey, MEMOBJ_INT); - }else{ - SyBlobReset(&pKey->sBlob); - SyBlobAppend(&pKey->sBlob, SyBlobData(&pNode->xKey.sKey), SyBlobLength(&pNode->xKey.sKey)); - MemObjSetType(pKey, MEMOBJ_STRING); - } -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -/* - * Store the address of nodes value in the given container. - * Refer to the [vfprintf(), vprintf(), vsprintf()] implementations - * defined in 'builtin.c' for more information. - */ -JX9_PRIVATE int jx9HashmapValuesToSet(jx9_hashmap *pMap, SySet *pOut) -{ - jx9_hashmap_node *pEntry = pMap->pFirst; - jx9_value *pValue; - sxu32 n; - /* Initialize the container */ - SySetInit(pOut, &pMap->pVm->sAllocator, sizeof(jx9_value *)); - for(n = 0 ; n < pMap->nEntry ; n++ ){ - /* Extract node value */ - pValue = HashmapExtractNodeValue(pEntry); - if( pValue ){ - SySetPut(pOut, (const void *)&pValue); - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - /* Total inserted entries */ - return (int)SySetUsed(pOut); -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* - * Merge sort. - * The merge sort implementation is based on the one found in the SQLite3 source tree. - * Status: Public domain - */ -/* Node comparison callback signature */ -typedef sxi32 (*ProcNodeCmp)(jx9_hashmap_node *, jx9_hashmap_node *, void *); -/* -** Inputs: -** a: A sorted, null-terminated linked list. (May be null). -** b: A sorted, null-terminated linked list. (May be null). -** cmp: A pointer to the comparison function. -** -** Return Value: -** A pointer to the head of a sorted list containing the elements -** of both a and b. -** -** Side effects: -** The "next", "prev" pointers for elements in the lists a and b are -** changed. -*/ -static jx9_hashmap_node * HashmapNodeMerge(jx9_hashmap_node *pA, jx9_hashmap_node *pB, ProcNodeCmp xCmp, void *pCmpData) -{ - jx9_hashmap_node result, *pTail; - /* Prevent compiler warning */ - result.pNext = result.pPrev = 0; - pTail = &result; - while( pA && pB ){ - if( xCmp(pA, pB, pCmpData) < 0 ){ - pTail->pPrev = pA; - pA->pNext = pTail; - pTail = pA; - pA = pA->pPrev; - }else{ - pTail->pPrev = pB; - pB->pNext = pTail; - pTail = pB; - pB = pB->pPrev; - } - } - if( pA ){ - pTail->pPrev = pA; - pA->pNext = pTail; - }else if( pB ){ - pTail->pPrev = pB; - pB->pNext = pTail; - }else{ - pTail->pPrev = pTail->pNext = 0; - } - return result.pPrev; -} -/* -** Inputs: -** Map: Input hashmap -** cmp: A comparison function. -** -** Return Value: -** Sorted hashmap. -** -** Side effects: -** The "next" pointers for elements in list are changed. -*/ -#define N_SORT_BUCKET 32 -static sxi32 HashmapMergeSort(jx9_hashmap *pMap, ProcNodeCmp xCmp, void *pCmpData) -{ - jx9_hashmap_node *a[N_SORT_BUCKET], *p, *pIn; - sxu32 i; - SyZero(a, sizeof(a)); - /* Point to the first inserted entry */ - pIn = pMap->pFirst; - while( pIn ){ - p = pIn; - pIn = p->pPrev; - p->pPrev = 0; - for(i=0; ipNext = 0; - /* Reflect the change */ - pMap->pFirst = p; - /* Reset the loop cursor */ - pMap->pCur = pMap->pFirst; - return SXRET_OK; -} -/* - * Node comparison callback. - * used-by: [sort(), asort(), ...] - */ -static sxi32 HashmapCmpCallback1(jx9_hashmap_node *pA, jx9_hashmap_node *pB, void *pCmpData) -{ - jx9_value sA, sB; - sxi32 iFlags; - int rc; - if( pCmpData == 0 ){ - /* Perform a standard comparison */ - rc = HashmapNodeCmp(pA, pB, FALSE); - return rc; - } - iFlags = SX_PTR_TO_INT(pCmpData); - /* Duplicate node values */ - jx9MemObjInit(pA->pMap->pVm, &sA); - jx9MemObjInit(pA->pMap->pVm, &sB); - jx9HashmapExtractNodeValue(pA, &sA, FALSE); - jx9HashmapExtractNodeValue(pB, &sB, FALSE); - if( iFlags == 5 ){ - /* String cast */ - if( (sA.iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(&sA); - } - if( (sB.iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(&sB); - } - }else{ - /* Numeric cast */ - jx9MemObjToNumeric(&sA); - jx9MemObjToNumeric(&sB); - } - /* Perform the comparison */ - rc = jx9MemObjCmp(&sA, &sB, FALSE, 0); - jx9MemObjRelease(&sA); - jx9MemObjRelease(&sB); - return rc; -} -/* - * Node comparison callback. - * Used by: [rsort(), arsort()]; - */ -static sxi32 HashmapCmpCallback3(jx9_hashmap_node *pA, jx9_hashmap_node *pB, void *pCmpData) -{ - jx9_value sA, sB; - sxi32 iFlags; - int rc; - if( pCmpData == 0 ){ - /* Perform a standard comparison */ - rc = HashmapNodeCmp(pA, pB, FALSE); - return -rc; - } - iFlags = SX_PTR_TO_INT(pCmpData); - /* Duplicate node values */ - jx9MemObjInit(pA->pMap->pVm, &sA); - jx9MemObjInit(pA->pMap->pVm, &sB); - jx9HashmapExtractNodeValue(pA, &sA, FALSE); - jx9HashmapExtractNodeValue(pB, &sB, FALSE); - if( iFlags == 5 ){ - /* String cast */ - if( (sA.iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(&sA); - } - if( (sB.iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(&sB); - } - }else{ - /* Numeric cast */ - jx9MemObjToNumeric(&sA); - jx9MemObjToNumeric(&sB); - } - /* Perform the comparison */ - rc = jx9MemObjCmp(&sA, &sB, FALSE, 0); - jx9MemObjRelease(&sA); - jx9MemObjRelease(&sB); - return -rc; -} -/* - * Node comparison callback: Invoke an user-defined callback for the purpose of node comparison. - * used-by: [usort(), uasort()] - */ -static sxi32 HashmapCmpCallback4(jx9_hashmap_node *pA, jx9_hashmap_node *pB, void *pCmpData) -{ - jx9_value sResult, *pCallback; - jx9_value *pV1, *pV2; - jx9_value *apArg[2]; /* Callback arguments */ - sxi32 rc; - /* Point to the desired callback */ - pCallback = (jx9_value *)pCmpData; - /* initialize the result value */ - jx9MemObjInit(pA->pMap->pVm, &sResult); - /* Extract nodes values */ - pV1 = HashmapExtractNodeValue(pA); - pV2 = HashmapExtractNodeValue(pB); - apArg[0] = pV1; - apArg[1] = pV2; - /* Invoke the callback */ - rc = jx9VmCallUserFunction(pA->pMap->pVm, pCallback, 2, apArg, &sResult); - if( rc != SXRET_OK ){ - /* An error occured while calling user defined function [i.e: not defined] */ - rc = -1; /* Set a dummy result */ - }else{ - /* Extract callback result */ - if((sResult.iFlags & MEMOBJ_INT) == 0 ){ - /* Perform an int cast */ - jx9MemObjToInteger(&sResult); - } - rc = (sxi32)sResult.x.iVal; - } - jx9MemObjRelease(&sResult); - /* Callback result */ - return rc; -} -/* - * Rehash all nodes keys after a merge-sort have been applied. - * Used by [sort(), usort() and rsort()]. - */ -static void HashmapSortRehash(jx9_hashmap *pMap) -{ - jx9_hashmap_node *p, *pLast; - sxu32 i; - /* Rehash all entries */ - pLast = p = pMap->pFirst; - pMap->iNextIdx = 0; /* Reset the automatic index */ - i = 0; - for( ;; ){ - if( i >= pMap->nEntry ){ - pMap->pLast = pLast; /* Fix the last link broken by the merge-sort */ - break; - } - if( p->iType == HASHMAP_BLOB_NODE ){ - /* Do not maintain index association as requested by the JX9 specification */ - SyBlobRelease(&p->xKey.sKey); - /* Change key type */ - p->iType = HASHMAP_INT_NODE; - } - HashmapRehashIntNode(p); - /* Point to the next entry */ - i++; - pLast = p; - p = p->pPrev; /* Reverse link */ - } -} -/* - * Array functions implementation. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * bool sort(array &$array[, int $sort_flags = SORT_REGULAR ] ) - * Sort an array. - * Parameters - * $array - * The input array. - * $sort_flags - * The optional second parameter sort_flags may be used to modify the sorting behavior using these values: - * Sorting type flags: - * SORT_REGULAR - compare items normally (don't change types) - * SORT_NUMERIC - compare items numerically - * SORT_STRING - compare items as strings - * Return - * TRUE on success or FALSE on failure. - * - */ -static int jx9_hashmap_sort(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - /* Make sure we are dealing with a valid hashmap */ - if( nArg < 1 || !jx9_value_is_json_array(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry > 1 ){ - sxi32 iCmpFlags = 0; - if( nArg > 1 ){ - /* Extract comparison flags */ - iCmpFlags = jx9_value_to_int(apArg[1]); - if( iCmpFlags == 3 /* SORT_REGULAR */ ){ - iCmpFlags = 0; /* Standard comparison */ - } - } - /* Do the merge sort */ - HashmapMergeSort(pMap, HashmapCmpCallback1, SX_INT_TO_PTR(iCmpFlags)); - /* Rehash [Do not maintain index association as requested by the JX9 specification] */ - HashmapSortRehash(pMap); - } - /* All done, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * bool rsort(array &$array[, int $sort_flags = SORT_REGULAR ] ) - * Sort an array in reverse order. - * Parameters - * $array - * The input array. - * $sort_flags - * The optional second parameter sort_flags may be used to modify the sorting behavior using these values: - * Sorting type flags: - * SORT_REGULAR - compare items normally (don't change types) - * SORT_NUMERIC - compare items numerically - * SORT_STRING - compare items as strings - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9_hashmap_rsort(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - /* Make sure we are dealing with a valid hashmap */ - if( nArg < 1 || !jx9_value_is_json_array(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry > 1 ){ - sxi32 iCmpFlags = 0; - if( nArg > 1 ){ - /* Extract comparison flags */ - iCmpFlags = jx9_value_to_int(apArg[1]); - if( iCmpFlags == 3 /* SORT_REGULAR */ ){ - iCmpFlags = 0; /* Standard comparison */ - } - } - /* Do the merge sort */ - HashmapMergeSort(pMap, HashmapCmpCallback3, SX_INT_TO_PTR(iCmpFlags)); - /* Rehash [Do not maintain index association as requested by the JX9 specification] */ - HashmapSortRehash(pMap); - } - /* All done, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * bool usort(array &$array, callable $cmp_function) - * Sort an array by values using a user-defined comparison function. - * Parameters - * $array - * The input array. - * $cmp_function - * The comparison function must return an integer less than, equal to, or greater - * than zero if the first argument is considered to be respectively less than, equal - * to, or greater than the second. - * int callback ( mixed $a, mixed $b ) - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9_hashmap_usort(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - /* Make sure we are dealing with a valid hashmap */ - if( nArg < 1 || !jx9_value_is_json_array(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry > 1 ){ - jx9_value *pCallback = 0; - ProcNodeCmp xCmp; - xCmp = HashmapCmpCallback4; /* User-defined function as the comparison callback */ - if( nArg > 1 && jx9_value_is_callable(apArg[1]) ){ - /* Point to the desired callback */ - pCallback = apArg[1]; - }else{ - /* Use the default comparison function */ - xCmp = HashmapCmpCallback1; - } - /* Do the merge sort */ - HashmapMergeSort(pMap, xCmp, pCallback); - /* Rehash [Do not maintain index association as requested by the JX9 specification] */ - HashmapSortRehash(pMap); - } - /* All done, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * int count(array $var [, int $mode = COUNT_NORMAL ]) - * Count all elements in an array, or something in an object. - * Parameters - * $var - * The array or the object. - * $mode - * If the optional mode parameter is set to COUNT_RECURSIVE (or 1), count() - * will recursively count the array. This is particularly useful for counting - * all the elements of a multidimensional array. count() does not detect infinite - * recursion. - * Return - * Returns the number of elements in the array. - */ -static int jx9_hashmap_count(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int bRecursive = FALSE; - sxi64 iCount; - if( nArg < 1 ){ - /* Missing arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - if( !jx9_value_is_json_array(apArg[0]) ){ - /* TICKET 1433-19: Handle objects */ - int res = !jx9_value_is_null(apArg[0]); - jx9_result_int(pCtx, res); - return JX9_OK; - } - if( nArg > 1 ){ - /* Recursive count? */ - bRecursive = jx9_value_to_int(apArg[1]) == 1 /* COUNT_RECURSIVE */; - } - /* Count */ - iCount = HashmapCount((jx9_hashmap *)apArg[0]->x.pOther, bRecursive, 0); - jx9_result_int64(pCtx, iCount); - return JX9_OK; -} -/* - * bool array_key_exists(value $key, array $search) - * Checks if the given key or index exists in the array. - * Parameters - * $key - * Value to check. - * $search - * An array with keys to check. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9_hashmap_key_exists(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - sxi32 rc; - if( nArg < 2 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[1]) ){ - /* Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the lookup */ - rc = jx9HashmapLookup((jx9_hashmap *)apArg[1]->x.pOther, apArg[0], 0); - /* lookup result */ - jx9_result_bool(pCtx, rc == SXRET_OK ? 1 : 0); - return JX9_OK; -} -/* - * value array_pop(array $array) - * POP the last inserted element from the array. - * Parameter - * The array to get the value from. - * Return - * Poped value or NULL on failure. - */ -static int jx9_hashmap_pop(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry < 1 ){ - /* Noting to pop, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_hashmap_node *pLast = pMap->pLast; - jx9_value *pObj; - pObj = HashmapExtractNodeValue(pLast); - if( pObj ){ - /* Node value */ - jx9_result_value(pCtx, pObj); - /* Unlink the node */ - jx9HashmapUnlinkNode(pLast); - }else{ - jx9_result_null(pCtx); - } - /* Reset the cursor */ - pMap->pCur = pMap->pFirst; - } - return JX9_OK; -} -/* - * int array_push($array, $var, ...) - * Push one or more elements onto the end of array. (Stack insertion) - * Parameters - * array - * The input array. - * var - * On or more value to push. - * Return - * New array count (including old items). - */ -static int jx9_hashmap_push(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - sxi32 rc; - int i; - if( nArg < 1 ){ - /* Missing arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - /* Start pushing given values */ - for( i = 1 ; i < nArg ; ++i ){ - rc = jx9HashmapInsert(pMap, 0, apArg[i]); - if( rc != SXRET_OK ){ - break; - } - } - /* Return the new count */ - jx9_result_int64(pCtx, (sxi64)pMap->nEntry); - return JX9_OK; -} -/* - * value array_shift(array $array) - * Shift an element off the beginning of array. - * Parameter - * The array to get the value from. - * Return - * Shifted value or NULL on failure. - */ -static int jx9_hashmap_shift(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Point to the internal representation of the hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry < 1 ){ - /* Empty hashmap, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_hashmap_node *pEntry = pMap->pFirst; - jx9_value *pObj; - sxu32 n; - pObj = HashmapExtractNodeValue(pEntry); - if( pObj ){ - /* Node value */ - jx9_result_value(pCtx, pObj); - /* Unlink the first node */ - jx9HashmapUnlinkNode(pEntry); - }else{ - jx9_result_null(pCtx); - } - /* Rehash all int keys */ - n = pMap->nEntry; - pEntry = pMap->pFirst; - pMap->iNextIdx = 0; /* Reset the automatic index */ - for(;;){ - if( n < 1 ){ - break; - } - if( pEntry->iType == HASHMAP_INT_NODE ){ - HashmapRehashIntNode(pEntry); - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - n--; - } - /* Reset the cursor */ - pMap->pCur = pMap->pFirst; - } - return JX9_OK; -} -/* - * Extract the node cursor value. - */ -static sxi32 HashmapCurrentValue(jx9_context *pCtx, jx9_hashmap *pMap, int iDirection) -{ - jx9_hashmap_node *pCur = pMap->pCur; - jx9_value *pVal; - if( pCur == 0 ){ - /* Cursor does not point to anything, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( iDirection != 0 ){ - if( iDirection > 0 ){ - /* Point to the next entry */ - pMap->pCur = pCur->pPrev; /* Reverse link */ - pCur = pMap->pCur; - }else{ - /* Point to the previous entry */ - pMap->pCur = pCur->pNext; /* Reverse link */ - pCur = pMap->pCur; - } - if( pCur == 0 ){ - /* End of input reached, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - } - /* Point to the desired element */ - pVal = HashmapExtractNodeValue(pCur); - if( pVal ){ - jx9_result_value(pCtx, pVal); - }else{ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * value current(array $array) - * Return the current element in an array. - * Parameter - * $input: The input array. - * Return - * The current() function simply returns the value of the array element that's currently - * being pointed to by the internal pointer. It does not move the pointer in any way. - * If the internal pointer points beyond the end of the elements list or the array - * is empty, current() returns FALSE. - */ -static int jx9_hashmap_current(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - HashmapCurrentValue(&(*pCtx), (jx9_hashmap *)apArg[0]->x.pOther, 0); - return JX9_OK; -} -/* - * value next(array $input) - * Advance the internal array pointer of an array. - * Parameter - * $input: The input array. - * Return - * next() behaves like current(), with one difference. It advances the internal array - * pointer one place forward before returning the element value. That means it returns - * the next array value and advances the internal array pointer by one. - */ -static int jx9_hashmap_next(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - HashmapCurrentValue(&(*pCtx), (jx9_hashmap *)apArg[0]->x.pOther, 1); - return JX9_OK; -} -/* - * value prev(array $input) - * Rewind the internal array pointer. - * Parameter - * $input: The input array. - * Return - * Returns the array value in the previous place that's pointed - * to by the internal array pointer, or FALSE if there are no more - * elements. - */ -static int jx9_hashmap_prev(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - HashmapCurrentValue(&(*pCtx), (jx9_hashmap *)apArg[0]->x.pOther, -1); - return JX9_OK; -} -/* - * value end(array $input) - * Set the internal pointer of an array to its last element. - * Parameter - * $input: The input array. - * Return - * Returns the value of the last element or FALSE for empty array. - */ -static int jx9_hashmap_end(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - /* Point to the last node */ - pMap->pCur = pMap->pLast; - /* Return the last node value */ - HashmapCurrentValue(&(*pCtx), pMap, 0); - return JX9_OK; -} -/* - * value reset(array $array ) - * Set the internal pointer of an array to its first element. - * Parameter - * $input: The input array. - * Return - * Returns the value of the first array element, or FALSE if the array is empty. - */ -static int jx9_hashmap_reset(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - /* Point to the first node */ - pMap->pCur = pMap->pFirst; - /* Return the last node value if available */ - HashmapCurrentValue(&(*pCtx), pMap, 0); - return JX9_OK; -} -/* - * value key(array $array) - * Fetch a key from an array - * Parameter - * $input - * The input array. - * Return - * The key() function simply returns the key of the array element that's currently - * being pointed to by the internal pointer. It does not move the pointer in any way. - * If the internal pointer points beyond the end of the elements list or the array - * is empty, key() returns NULL. - */ -static int jx9_hashmap_simple_key(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap_node *pCur; - jx9_hashmap *pMap; - if( nArg < 1 ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - pCur = pMap->pCur; - if( pCur == 0 ){ - /* Cursor does not point to anything, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - if( pCur->iType == HASHMAP_INT_NODE){ - /* Key is integer */ - jx9_result_int64(pCtx, pCur->xKey.iKey); - }else{ - /* Key is blob */ - jx9_result_string(pCtx, - (const char *)SyBlobData(&pCur->xKey.sKey), (int)SyBlobLength(&pCur->xKey.sKey)); - } - return JX9_OK; -} -/* - * array each(array $input) - * Return the current key and value pair from an array and advance the array cursor. - * Parameter - * $input - * The input array. - * Return - * Returns the current key and value pair from the array array. This pair is returned - * in a four-element array, with the keys 0, 1, key, and value. Elements 0 and key - * contain the key name of the array element, and 1 and value contain the data. - * If the internal pointer for the array points past the end of the array contents - * each() returns FALSE. - */ -static int jx9_hashmap_each(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap_node *pCur; - jx9_hashmap *pMap; - jx9_value *pArray; - jx9_value *pVal; - jx9_value sKey; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the internal representation that describe the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->pCur == 0 ){ - /* Cursor does not point to anything, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pCur = pMap->pCur; - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pVal = HashmapExtractNodeValue(pCur); - /* Insert the current value */ - jx9_array_add_strkey_elem(pArray, "1", pVal); - jx9_array_add_strkey_elem(pArray, "value", pVal); - /* Make the key */ - if( pCur->iType == HASHMAP_INT_NODE ){ - jx9MemObjInitFromInt(pMap->pVm, &sKey, pCur->xKey.iKey); - }else{ - jx9MemObjInitFromString(pMap->pVm, &sKey, 0); - jx9MemObjStringAppend(&sKey, (const char *)SyBlobData(&pCur->xKey.sKey), SyBlobLength(&pCur->xKey.sKey)); - } - /* Insert the current key */ - jx9_array_add_elem(pArray, 0, &sKey); - jx9_array_add_strkey_elem(pArray, "key", &sKey); - jx9MemObjRelease(&sKey); - /* Advance the cursor */ - pMap->pCur = pCur->pPrev; /* Reverse link */ - /* Return the current entry */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * array array_values(array $input) - * Returns all the values from the input array and indexes numerically the array. - * Parameters - * input: The input array. - * Return - * An indexed array of values or NULL on failure. - */ -static int jx9_hashmap_values(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap_node *pNode; - jx9_hashmap *pMap; - jx9_value *pArray; - jx9_value *pObj; - sxu32 n; - if( nArg < 1 ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Point to the internal representation that describe the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Perform the requested operation */ - pNode = pMap->pFirst; - for( n = 0 ; n < pMap->nEntry ; ++n ){ - pObj = HashmapExtractNodeValue(pNode); - if( pObj ){ - /* perform the insertion */ - jx9_array_add_elem(pArray, 0/* Automatic index assign */, pObj); - } - /* Point to the next entry */ - pNode = pNode->pPrev; /* Reverse link */ - } - /* return the new array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * bool array_same(array $arr1, array $arr2) - * Return TRUE if the given arrays are the same instance. - * This function is useful under JX9 since arrays and objects - * are passed by reference. - * Parameters - * $arr1 - * First array - * $arr2 - * Second array - * Return - * TRUE if the arrays are the same instance. FALSE otherwise. - * Note - * This function is a symisc eXtension. - */ -static int jx9_hashmap_same(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *p1, *p2; - int rc; - if( nArg < 2 || !jx9_value_is_json_array(apArg[0]) || !jx9_value_is_json_array(apArg[1]) ){ - /* Missing or invalid arguments, return FALSE*/ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the hashmaps */ - p1 = (jx9_hashmap *)apArg[0]->x.pOther; - p2 = (jx9_hashmap *)apArg[1]->x.pOther; - rc = (p1 == p2); - /* Same instance? */ - jx9_result_bool(pCtx, rc); - return JX9_OK; -} -/* - * array array_merge(array $array1, ...) - * Merge one or more arrays. - * Parameters - * $array1 - * Initial array to merge. - * ... - * More array to merge. - * Return - * The resulting array. - */ -static int jx9_hashmap_merge(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap, *pSrc; - jx9_value *pArray; - int i; - if( nArg < 1 ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Point to the internal representation of the hashmap */ - pMap = (jx9_hashmap *)pArray->x.pOther; - /* Start merging */ - for( i = 0 ; i < nArg ; i++ ){ - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[i]) ){ - /* Insert scalar value */ - jx9_array_add_elem(pArray, 0, apArg[i]); - }else{ - pSrc = (jx9_hashmap *)apArg[i]->x.pOther; - /* Merge the two hashmaps */ - HashmapMerge(pSrc, pMap); - } - } - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * bool in_array(value $needle, array $haystack[, bool $strict = FALSE ]) - * Checks if a value exists in an array. - * Parameters - * $needle - * The searched value. - * Note: - * If needle is a string, the comparison is done in a case-sensitive manner. - * $haystack - * The target array. - * $strict - * If the third parameter strict is set to TRUE then the in_array() function - * will also check the types of the needle in the haystack. - */ -static int jx9_hashmap_in_array(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pNeedle; - int bStrict; - int rc; - if( nArg < 2 ){ - /* Missing argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pNeedle = apArg[0]; - bStrict = 0; - if( nArg > 2 ){ - bStrict = jx9_value_to_bool(apArg[2]); - } - if( !jx9_value_is_json_array(apArg[1]) ){ - /* haystack must be an array, perform a standard comparison */ - rc = jx9_value_compare(pNeedle, apArg[1], bStrict); - /* Set the comparison result */ - jx9_result_bool(pCtx, rc == 0); - return JX9_OK; - } - /* Perform the lookup */ - rc = HashmapFindValue((jx9_hashmap *)apArg[1]->x.pOther, pNeedle, 0, bStrict); - /* Lookup result */ - jx9_result_bool(pCtx, rc == SXRET_OK); - return JX9_OK; -} -/* - * array array_copy(array $source) - * Make a blind copy of the target array. - * Parameters - * $source - * Target array - * Return - * Copy of the target array on success. NULL otherwise. - * Note - * This function is a symisc eXtension. - */ -static int jx9_hashmap_copy(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - jx9_value *pArray; - if( nArg < 1 ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Point to the internal representation of the hashmap */ - pMap = (jx9_hashmap *)pArray->x.pOther; - if( jx9_value_is_json_array(apArg[0])){ - /* Point to the internal representation of the source */ - jx9_hashmap *pSrc = (jx9_hashmap *)apArg[0]->x.pOther; - /* Perform the copy */ - jx9HashmapDup(pSrc, pMap); - }else{ - /* Simple insertion */ - jx9HashmapInsert(pMap, 0/* Automatic index assign*/, apArg[0]); - } - /* Return the duplicated array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * bool array_erase(array $source) - * Remove all elements from a given array. - * Parameters - * $source - * Target array - * Return - * TRUE on success. FALSE otherwise. - * Note - * This function is a symisc eXtension. - */ -static int jx9_hashmap_erase(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - if( nArg < 1 ){ - /* Missing arguments */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - /* Erase */ - jx9HashmapRelease(pMap, FALSE); - return JX9_OK; -} -/* - * array array_diff(array $array1, array $array2, ...) - * Computes the difference of arrays. - * Parameters - * $array1 - * The array to compare from - * $array2 - * An array to compare against - * $... - * More arrays to compare against - * Return - * Returns an array containing all the entries from array1 that - * are not present in any of the other arrays. - */ -static int jx9_hashmap_diff(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap_node *pEntry; - jx9_hashmap *pSrc, *pMap; - jx9_value *pArray; - jx9_value *pVal; - sxi32 rc; - sxu32 n; - int i; - if( nArg < 1 || !jx9_value_is_json_array(apArg[0]) ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - if( nArg == 1 ){ - /* Return the first array since we cannot perform a diff */ - jx9_result_value(pCtx, apArg[0]); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Point to the internal representation of the source hashmap */ - pSrc = (jx9_hashmap *)apArg[0]->x.pOther; - /* Perform the diff */ - pEntry = pSrc->pFirst; - n = pSrc->nEntry; - for(;;){ - if( n < 1 ){ - break; - } - /* Extract the node value */ - pVal = HashmapExtractNodeValue(pEntry); - if( pVal ){ - for( i = 1 ; i < nArg ; i++ ){ - if( !jx9_value_is_json_array(apArg[i])) { - /* ignore */ - continue; - } - /* Point to the internal representation of the hashmap */ - pMap = (jx9_hashmap *)apArg[i]->x.pOther; - /* Perform the lookup */ - rc = HashmapFindValue(pMap, pVal, 0, TRUE); - if( rc == SXRET_OK ){ - /* Value exist */ - break; - } - } - if( i >= nArg ){ - /* Perform the insertion */ - HashmapInsertNode((jx9_hashmap *)pArray->x.pOther, pEntry, TRUE); - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - n--; - } - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * array array_intersect(array $array1 , array $array2, ...) - * Computes the intersection of arrays. - * Parameters - * $array1 - * The array to compare from - * $array2 - * An array to compare against - * $... - * More arrays to compare against - * Return - * Returns an array containing all of the values in array1 whose values exist - * in all of the parameters. . - * Note that NULL is returned on failure. - */ -static int jx9_hashmap_intersect(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap_node *pEntry; - jx9_hashmap *pSrc, *pMap; - jx9_value *pArray; - jx9_value *pVal; - sxi32 rc; - sxu32 n; - int i; - if( nArg < 1 || !jx9_value_is_json_array(apArg[0]) ){ - /* Missing arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - if( nArg == 1 ){ - /* Return the first array since we cannot perform a diff */ - jx9_result_value(pCtx, apArg[0]); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Point to the internal representation of the source hashmap */ - pSrc = (jx9_hashmap *)apArg[0]->x.pOther; - /* Perform the intersection */ - pEntry = pSrc->pFirst; - n = pSrc->nEntry; - for(;;){ - if( n < 1 ){ - break; - } - /* Extract the node value */ - pVal = HashmapExtractNodeValue(pEntry); - if( pVal ){ - for( i = 1 ; i < nArg ; i++ ){ - if( !jx9_value_is_json_array(apArg[i])) { - /* ignore */ - continue; - } - /* Point to the internal representation of the hashmap */ - pMap = (jx9_hashmap *)apArg[i]->x.pOther; - /* Perform the lookup */ - rc = HashmapFindValue(pMap, pVal, 0, TRUE); - if( rc != SXRET_OK ){ - /* Value does not exist */ - break; - } - } - if( i >= nArg ){ - /* Perform the insertion */ - HashmapInsertNode((jx9_hashmap *)pArray->x.pOther, pEntry, TRUE); - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - n--; - } - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * number array_sum(array $array ) - * Calculate the sum of values in an array. - * Parameters - * $array: The input array. - * Return - * Returns the sum of values as an integer or float. - */ -static void DoubleSum(jx9_context *pCtx, jx9_hashmap *pMap) -{ - jx9_hashmap_node *pEntry; - jx9_value *pObj; - double dSum = 0; - sxu32 n; - pEntry = pMap->pFirst; - for( n = 0 ; n < pMap->nEntry ; n++ ){ - pObj = HashmapExtractNodeValue(pEntry); - if( pObj && (pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_RES)) == 0){ - if( pObj->iFlags & MEMOBJ_REAL ){ - dSum += pObj->x.rVal; - }else if( pObj->iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){ - dSum += (double)pObj->x.iVal; - }else if( pObj->iFlags & MEMOBJ_STRING ){ - if( SyBlobLength(&pObj->sBlob) > 0 ){ - double dv = 0; - SyStrToReal((const char *)SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob), (void *)&dv, 0); - dSum += dv; - } - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - /* Return sum */ - jx9_result_double(pCtx, dSum); -} -static void Int64Sum(jx9_context *pCtx, jx9_hashmap *pMap) -{ - jx9_hashmap_node *pEntry; - jx9_value *pObj; - sxi64 nSum = 0; - sxu32 n; - pEntry = pMap->pFirst; - for( n = 0 ; n < pMap->nEntry ; n++ ){ - pObj = HashmapExtractNodeValue(pEntry); - if( pObj && (pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_RES)) == 0){ - if( pObj->iFlags & MEMOBJ_REAL ){ - nSum += (sxi64)pObj->x.rVal; - }else if( pObj->iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){ - nSum += pObj->x.iVal; - }else if( pObj->iFlags & MEMOBJ_STRING ){ - if( SyBlobLength(&pObj->sBlob) > 0 ){ - sxi64 nv = 0; - SyStrToInt64((const char *)SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob), (void *)&nv, 0); - nSum += nv; - } - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - /* Return sum */ - jx9_result_int64(pCtx, nSum); -} -/* number array_sum(array $array ) - * (See block-coment above) - */ -static int jx9_hashmap_sum(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - jx9_value *pObj; - if( nArg < 1 ){ - /* Missing arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry < 1 ){ - /* Nothing to compute, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* If the first element is of type float, then perform floating - * point computaion.Otherwise switch to int64 computaion. - */ - pObj = HashmapExtractNodeValue(pMap->pFirst); - if( pObj == 0 ){ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - if( pObj->iFlags & MEMOBJ_REAL ){ - DoubleSum(pCtx, pMap); - }else{ - Int64Sum(pCtx, pMap); - } - return JX9_OK; -} -/* - * number array_product(array $array ) - * Calculate the product of values in an array. - * Parameters - * $array: The input array. - * Return - * Returns the product of values as an integer or float. - */ -static void DoubleProd(jx9_context *pCtx, jx9_hashmap *pMap) -{ - jx9_hashmap_node *pEntry; - jx9_value *pObj; - double dProd; - sxu32 n; - pEntry = pMap->pFirst; - dProd = 1; - for( n = 0 ; n < pMap->nEntry ; n++ ){ - pObj = HashmapExtractNodeValue(pEntry); - if( pObj && (pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_RES)) == 0){ - if( pObj->iFlags & MEMOBJ_REAL ){ - dProd *= pObj->x.rVal; - }else if( pObj->iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){ - dProd *= (double)pObj->x.iVal; - }else if( pObj->iFlags & MEMOBJ_STRING ){ - if( SyBlobLength(&pObj->sBlob) > 0 ){ - double dv = 0; - SyStrToReal((const char *)SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob), (void *)&dv, 0); - dProd *= dv; - } - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - /* Return product */ - jx9_result_double(pCtx, dProd); -} -static void Int64Prod(jx9_context *pCtx, jx9_hashmap *pMap) -{ - jx9_hashmap_node *pEntry; - jx9_value *pObj; - sxi64 nProd; - sxu32 n; - pEntry = pMap->pFirst; - nProd = 1; - for( n = 0 ; n < pMap->nEntry ; n++ ){ - pObj = HashmapExtractNodeValue(pEntry); - if( pObj && (pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_RES)) == 0){ - if( pObj->iFlags & MEMOBJ_REAL ){ - nProd *= (sxi64)pObj->x.rVal; - }else if( pObj->iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){ - nProd *= pObj->x.iVal; - }else if( pObj->iFlags & MEMOBJ_STRING ){ - if( SyBlobLength(&pObj->sBlob) > 0 ){ - sxi64 nv = 0; - SyStrToInt64((const char *)SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob), (void *)&nv, 0); - nProd *= nv; - } - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - /* Return product */ - jx9_result_int64(pCtx, nProd); -} -/* number array_product(array $array ) - * (See block-block comment above) - */ -static int jx9_hashmap_product(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_hashmap *pMap; - jx9_value *pObj; - if( nArg < 1 ){ - /* Missing arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid hashmap */ - if( !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid argument, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry < 1 ){ - /* Nothing to compute, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* If the first element is of type float, then perform floating - * point computaion.Otherwise switch to int64 computaion. - */ - pObj = HashmapExtractNodeValue(pMap->pFirst); - if( pObj == 0 ){ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - if( pObj->iFlags & MEMOBJ_REAL ){ - DoubleProd(pCtx, pMap); - }else{ - Int64Prod(pCtx, pMap); - } - return JX9_OK; -} -/* - * array array_map(callback $callback, array $arr1) - * Applies the callback to the elements of the given arrays. - * Parameters - * $callback - * Callback function to run for each element in each array. - * $arr1 - * An array to run through the callback function. - * Return - * Returns an array containing all the elements of arr1 after applying - * the callback function to each one. - * NOTE: - * array_map() passes only a single value to the callback. - */ -static int jx9_hashmap_map(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue, sKey, sResult; - jx9_hashmap_node *pEntry; - jx9_hashmap *pMap; - sxu32 n; - if( nArg < 2 || !jx9_value_is_json_array(apArg[1]) ){ - /* Invalid arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[1]->x.pOther; - jx9MemObjInit(pMap->pVm, &sResult); - jx9MemObjInit(pMap->pVm, &sKey); - /* Perform the requested operation */ - pEntry = pMap->pFirst; - for( n = 0 ; n < pMap->nEntry ; n++ ){ - /* Extrcat the node value */ - pValue = HashmapExtractNodeValue(pEntry); - if( pValue ){ - sxi32 rc; - /* Invoke the supplied callback */ - rc = jx9VmCallUserFunction(pMap->pVm, apArg[0], 1, &pValue, &sResult); - /* Extract the node key */ - jx9HashmapExtractNodeKey(pEntry, &sKey); - if( rc != SXRET_OK ){ - /* An error occured while invoking the supplied callback [i.e: not defined] */ - jx9_array_add_elem(pArray, &sKey, pValue); /* Keep the same value */ - }else{ - /* Insert the callback return value */ - jx9_array_add_elem(pArray, &sKey, &sResult); - } - jx9MemObjRelease(&sKey); - jx9MemObjRelease(&sResult); - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * bool array_walk(array &$array, callback $funcname [, value $userdata ] ) - * Apply a user function to every member of an array. - * Parameters - * $array - * The input array. - * $funcname - * Typically, funcname takes on two parameters.The array parameter's value being - * the first, and the key/index second. - * Note: - * If funcname needs to be working with the actual values of the array, specify the first - * parameter of funcname as a reference. Then, any changes made to those elements will - * be made in the original array itself. - * $userdata - * If the optional userdata parameter is supplied, it will be passed as the third parameter - * to the callback funcname. - * Return - * Returns TRUE on success or FALSE on failure. - */ -static int jx9_hashmap_walk(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pValue, *pUserData, sKey; - jx9_hashmap_node *pEntry; - jx9_hashmap *pMap; - sxi32 rc; - sxu32 n; - if( nArg < 2 || !jx9_value_is_json_array(apArg[0]) ){ - /* Invalid/Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pUserData = nArg > 2 ? apArg[2] : 0; - /* Point to the internal representation of the input hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - jx9MemObjInit(pMap->pVm, &sKey); - /* Perform the desired operation */ - pEntry = pMap->pFirst; - for( n = 0 ; n < pMap->nEntry ; n++ ){ - /* Extract the node value */ - pValue = HashmapExtractNodeValue(pEntry); - if( pValue ){ - /* Extract the entry key */ - jx9HashmapExtractNodeKey(pEntry, &sKey); - /* Invoke the supplied callback */ - rc = jx9VmCallUserFunctionAp(pMap->pVm, apArg[1], 0, pValue, &sKey, pUserData, 0); - jx9MemObjRelease(&sKey); - if( rc != SXRET_OK ){ - /* An error occured while invoking the supplied callback [i.e: not defined] */ - jx9_result_bool(pCtx, 0); /* return FALSE */ - return JX9_OK; - } - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - } - /* All done, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * Table of built-in hashmap functions. - */ -static const jx9_builtin_func aHashmapFunc[] = { - {"count", jx9_hashmap_count }, - {"sizeof", jx9_hashmap_count }, - {"array_key_exists", jx9_hashmap_key_exists }, - {"array_pop", jx9_hashmap_pop }, - {"array_push", jx9_hashmap_push }, - {"array_shift", jx9_hashmap_shift }, - {"array_product", jx9_hashmap_product }, - {"array_sum", jx9_hashmap_sum }, - {"array_values", jx9_hashmap_values }, - {"array_same", jx9_hashmap_same }, - {"array_merge", jx9_hashmap_merge }, - {"array_diff", jx9_hashmap_diff }, - {"array_intersect", jx9_hashmap_intersect}, - {"in_array", jx9_hashmap_in_array }, - {"array_copy", jx9_hashmap_copy }, - {"array_erase", jx9_hashmap_erase }, - {"array_map", jx9_hashmap_map }, - {"array_walk", jx9_hashmap_walk }, - {"sort", jx9_hashmap_sort }, - {"rsort", jx9_hashmap_rsort }, - {"usort", jx9_hashmap_usort }, - {"current", jx9_hashmap_current }, - {"each", jx9_hashmap_each }, - {"pos", jx9_hashmap_current }, - {"next", jx9_hashmap_next }, - {"prev", jx9_hashmap_prev }, - {"end", jx9_hashmap_end }, - {"reset", jx9_hashmap_reset }, - {"key", jx9_hashmap_simple_key } -}; -/* - * Register the built-in hashmap functions defined above. - */ -JX9_PRIVATE void jx9RegisterHashmapFunctions(jx9_vm *pVm) -{ - sxu32 n; - for( n = 0 ; n < SX_ARRAYSIZE(aHashmapFunc) ; n++ ){ - jx9_create_function(&(*pVm), aHashmapFunc[n].zName, aHashmapFunc[n].xFunc, 0); - } -} -/* - * Iterate throw hashmap entries and invoke the given callback [i.e: xWalk()] for each - * retrieved entry. - * Note that argument are passed to the callback by copy. That is, any modification to - * the entry value in the callback body will not alter the real value. - * If the callback wishes to abort processing [i.e: it's invocation] it must return - * a value different from JX9_OK. - * Refer to [jx9_array_walk()] for more information. - */ -JX9_PRIVATE sxi32 jx9HashmapWalk( - jx9_hashmap *pMap, /* Target hashmap */ - int (*xWalk)(jx9_value *, jx9_value *, void *), /* Walker callback */ - void *pUserData /* Last argument to xWalk() */ - ) -{ - jx9_hashmap_node *pEntry; - jx9_value sKey, sValue; - sxi32 rc; - sxu32 n; - /* Initialize walker parameter */ - rc = SXRET_OK; - jx9MemObjInit(pMap->pVm, &sKey); - jx9MemObjInit(pMap->pVm, &sValue); - n = pMap->nEntry; - pEntry = pMap->pFirst; - /* Start the iteration process */ - for(;;){ - if( n < 1 ){ - break; - } - /* Extract a copy of the key and a copy the current value */ - jx9HashmapExtractNodeKey(pEntry, &sKey); - jx9HashmapExtractNodeValue(pEntry, &sValue, FALSE); - /* Invoke the user callback */ - rc = xWalk(&sKey, &sValue, pUserData); - /* Release the copy of the key and the value */ - jx9MemObjRelease(&sKey); - jx9MemObjRelease(&sValue); - if( rc != JX9_OK ){ - /* Callback request an operation abort */ - return SXERR_ABORT; - } - /* Point to the next entry */ - pEntry = pEntry->pPrev; /* Reverse link */ - n--; - } - /* All done */ - return SXRET_OK; -} -/* - * ---------------------------------------------------------- - * File: jx9_json.c - * MD5: 31a27f8797418de511c669feed763341 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: json.c v1.0 FreeBSD 2012-12-16 00:28 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* This file deals with JSON serialization, decoding and stuff like that. */ -/* - * Section: - * JSON encoding/decoding routines. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Devel. - */ -/* Forward reference */ -static int VmJsonArrayEncode(jx9_value *pKey, jx9_value *pValue, void *pUserData); -static int VmJsonObjectEncode(jx9_value *pKey, jx9_value *pValue, void *pUserData); -/* - * JSON encoder state is stored in an instance - * of the following structure. - */ -typedef struct json_private_data json_private_data; -struct json_private_data -{ - SyBlob *pOut; /* Output consumer buffer */ - int isFirst; /* True if first encoded entry */ - int iFlags; /* JSON encoding flags */ - int nRecCount; /* Recursion count */ -}; -/* - * Returns the JSON representation of a value.In other word perform a JSON encoding operation. - * According to wikipedia - * JSON's basic types are: - * Number (double precision floating-point format in JavaScript, generally depends on implementation) - * String (double-quoted Unicode, with backslash escaping) - * Boolean (true or false) - * Array (an ordered sequence of values, comma-separated and enclosed in square brackets; the values - * do not need to be of the same type) - * Object (an unordered collection of key:value pairs with the ':' character separating the key - * and the value, comma-separated and enclosed in curly braces; the keys must be strings and should - * be distinct from each other) - * null (empty) - * Non-significant white space may be added freely around the "structural characters" - * (i.e. the brackets "[{]}", colon ":" and comma ","). - */ -static sxi32 VmJsonEncode( - jx9_value *pIn, /* Encode this value */ - json_private_data *pData /* Context data */ - ){ - SyBlob *pOut = pData->pOut; - int nByte; - if( jx9_value_is_null(pIn) || jx9_value_is_resource(pIn)){ - /* null */ - SyBlobAppend(pOut, "null", sizeof("null")-1); - }else if( jx9_value_is_bool(pIn) ){ - int iBool = jx9_value_to_bool(pIn); - sxu32 iLen; - /* true/false */ - iLen = iBool ? sizeof("true") : sizeof("false"); - SyBlobAppend(pOut, iBool ? "true" : "false", iLen-1); - }else if( jx9_value_is_numeric(pIn) && !jx9_value_is_string(pIn) ){ - const char *zNum; - /* Get a string representation of the number */ - zNum = jx9_value_to_string(pIn, &nByte); - SyBlobAppend(pOut,zNum,nByte); - }else if( jx9_value_is_string(pIn) ){ - const char *zIn, *zEnd; - int c; - /* Encode the string */ - zIn = jx9_value_to_string(pIn, &nByte); - zEnd = &zIn[nByte]; - /* Append the double quote */ - SyBlobAppend(pOut,"\"", sizeof(char)); - for(;;){ - if( zIn >= zEnd ){ - /* No more input to process */ - break; - } - c = zIn[0]; - /* Advance the stream cursor */ - zIn++; - if( c == '"' || c == '\\' ){ - /* Unescape the character */ - SyBlobAppend(pOut,"\\", sizeof(char)); - } - /* Append character verbatim */ - SyBlobAppend(pOut,(const char *)&c,sizeof(char)); - } - /* Append the double quote */ - SyBlobAppend(pOut,"\"",sizeof(char)); - }else if( jx9_value_is_json_array(pIn) ){ - /* Encode the array/object */ - pData->isFirst = 1; - if( jx9_value_is_json_object(pIn) ){ - /* Encode the object instance */ - pData->isFirst = 1; - /* Append the curly braces */ - SyBlobAppend(pOut, "{",sizeof(char)); - /* Iterate throw object attribute */ - jx9_array_walk(pIn,VmJsonObjectEncode, pData); - /* Append the closing curly braces */ - SyBlobAppend(pOut, "}",sizeof(char)); - }else{ - /* Append the square bracket or curly braces */ - SyBlobAppend(pOut,"[",sizeof(char)); - /* Iterate throw array entries */ - jx9_array_walk(pIn, VmJsonArrayEncode, pData); - /* Append the closing square bracket or curly braces */ - SyBlobAppend(pOut,"]",sizeof(char)); - } - }else{ - /* Can't happen */ - SyBlobAppend(pOut,"null",sizeof("null")-1); - } - /* All done */ - return JX9_OK; -} -/* - * The following walker callback is invoked each time we need - * to encode an array to JSON. - */ -static int VmJsonArrayEncode(jx9_value *pKey, jx9_value *pValue, void *pUserData) -{ - json_private_data *pJson = (json_private_data *)pUserData; - if( pJson->nRecCount > 31 ){ - /* Recursion limit reached, return immediately */ - SXUNUSED(pKey); /* cc warning */ - return JX9_OK; - } - if( !pJson->isFirst ){ - /* Append the colon first */ - SyBlobAppend(pJson->pOut,",",(int)sizeof(char)); - } - /* Encode the value */ - pJson->nRecCount++; - VmJsonEncode(pValue, pJson); - pJson->nRecCount--; - pJson->isFirst = 0; - return JX9_OK; -} -/* - * The following walker callback is invoked each time we need to encode - * a object instance [i.e: Object in the JX9 jargon] to JSON. - */ -static int VmJsonObjectEncode(jx9_value *pKey,jx9_value *pValue,void *pUserData) -{ - json_private_data *pJson = (json_private_data *)pUserData; - const char *zKey; - int nByte; - if( pJson->nRecCount > 31 ){ - /* Recursion limit reached, return immediately */ - return JX9_OK; - } - if( !pJson->isFirst ){ - /* Append the colon first */ - SyBlobAppend(pJson->pOut,",",sizeof(char)); - } - /* Extract a string representation of the key */ - zKey = jx9_value_to_string(pKey, &nByte); - /* Append the key and the double colon */ - if( nByte > 0 ){ - SyBlobAppend(pJson->pOut,"\"",sizeof(char)); - SyBlobAppend(pJson->pOut,zKey,(sxu32)nByte); - SyBlobAppend(pJson->pOut,"\"",sizeof(char)); - }else{ - /* Can't happen */ - SyBlobAppend(pJson->pOut,"null",sizeof("null")-1); - } - SyBlobAppend(pJson->pOut,":",sizeof(char)); - /* Encode the value */ - pJson->nRecCount++; - VmJsonEncode(pValue, pJson); - pJson->nRecCount--; - pJson->isFirst = 0; - return JX9_OK; -} -/* - * Returns a string containing the JSON representation of value. - * In other words, perform the serialization of the given JSON object. - */ -JX9_PRIVATE int jx9JsonSerialize(jx9_value *pValue,SyBlob *pOut) -{ - json_private_data sJson; - /* Prepare the JSON data */ - sJson.nRecCount = 0; - sJson.pOut = pOut; - sJson.isFirst = 1; - sJson.iFlags = 0; - /* Perform the encoding operation */ - VmJsonEncode(pValue, &sJson); - /* All done */ - return JX9_OK; -} -/* Possible tokens from the JSON tokenization process */ -#define JSON_TK_TRUE 0x001 /* Boolean true */ -#define JSON_TK_FALSE 0x002 /* Boolean false */ -#define JSON_TK_STR 0x004 /* String enclosed in double quotes */ -#define JSON_TK_NULL 0x008 /* null */ -#define JSON_TK_NUM 0x010 /* Numeric */ -#define JSON_TK_OCB 0x020 /* Open curly braces '{' */ -#define JSON_TK_CCB 0x040 /* Closing curly braces '}' */ -#define JSON_TK_OSB 0x080 /* Open square bracke '[' */ -#define JSON_TK_CSB 0x100 /* Closing square bracket ']' */ -#define JSON_TK_COLON 0x200 /* Single colon ':' */ -#define JSON_TK_COMMA 0x400 /* Single comma ',' */ -#define JSON_TK_ID 0x800 /* ID */ -#define JSON_TK_INVALID 0x1000 /* Unexpected token */ -/* - * Tokenize an entire JSON input. - * Get a single low-level token from the input file. - * Update the stream pointer so that it points to the first - * character beyond the extracted token. - */ -static sxi32 VmJsonTokenize(SyStream *pStream, SyToken *pToken, void *pUserData, void *pCtxData) -{ - int *pJsonErr = (int *)pUserData; - SyString *pStr; - int c; - /* Ignore leading white spaces */ - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisSpace(pStream->zText[0]) ){ - /* Advance the stream cursor */ - if( pStream->zText[0] == '\n' ){ - /* Update line counter */ - pStream->nLine++; - } - pStream->zText++; - } - if( pStream->zText >= pStream->zEnd ){ - /* End of input reached */ - SXUNUSED(pCtxData); /* cc warning */ - return SXERR_EOF; - } - /* Record token starting position and line */ - pToken->nLine = pStream->nLine; - pToken->pUserData = 0; - pStr = &pToken->sData; - SyStringInitFromBuf(pStr, pStream->zText, 0); - if( pStream->zText[0] >= 0xc0 || SyisAlpha(pStream->zText[0]) || pStream->zText[0] == '_' ){ - /* The following code fragment is taken verbatim from the xPP source tree. - * xPP is a modern embeddable macro processor with advanced features useful for - * application seeking for a production quality, ready to use macro processor. - * xPP is a widely used library developed and maintened by Symisc Systems. - * You can reach the xPP home page by following this link: - * http://xpp.symisc.net/ - */ - const unsigned char *zIn; - /* Isolate UTF-8 or alphanumeric stream */ - if( pStream->zText[0] < 0xc0 ){ - pStream->zText++; - } - for(;;){ - zIn = pStream->zText; - if( zIn[0] >= 0xc0 ){ - zIn++; - /* UTF-8 stream */ - while( zIn < pStream->zEnd && ((zIn[0] & 0xc0) == 0x80) ){ - zIn++; - } - } - /* Skip alphanumeric stream */ - while( zIn < pStream->zEnd && zIn[0] < 0xc0 && (SyisAlphaNum(zIn[0]) || zIn[0] == '_') ){ - zIn++; - } - if( zIn == pStream->zText ){ - /* Not an UTF-8 or alphanumeric stream */ - break; - } - /* Synchronize pointers */ - pStream->zText = zIn; - } - /* Record token length */ - pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); - /* A simple identifier */ - pToken->nType = JSON_TK_ID; - if( pStr->nByte == sizeof("true") -1 && SyStrnicmp(pStr->zString, "true", sizeof("true")-1) == 0 ){ - /* boolean true */ - pToken->nType = JSON_TK_TRUE; - }else if( pStr->nByte == sizeof("false") -1 && SyStrnicmp(pStr->zString,"false", sizeof("false")-1) == 0 ){ - /* boolean false */ - pToken->nType = JSON_TK_FALSE; - }else if( pStr->nByte == sizeof("null") -1 && SyStrnicmp(pStr->zString,"null", sizeof("null")-1) == 0 ){ - /* NULL */ - pToken->nType = JSON_TK_NULL; - } - return SXRET_OK; - } - if( pStream->zText[0] == '{' || pStream->zText[0] == '[' || pStream->zText[0] == '}' || pStream->zText[0] == ']' - || pStream->zText[0] == ':' || pStream->zText[0] == ',' ){ - /* Single character */ - c = pStream->zText[0]; - /* Set token type */ - switch(c){ - case '[': pToken->nType = JSON_TK_OSB; break; - case '{': pToken->nType = JSON_TK_OCB; break; - case '}': pToken->nType = JSON_TK_CCB; break; - case ']': pToken->nType = JSON_TK_CSB; break; - case ':': pToken->nType = JSON_TK_COLON; break; - case ',': pToken->nType = JSON_TK_COMMA; break; - default: - break; - } - /* Advance the stream cursor */ - pStream->zText++; - }else if( pStream->zText[0] == '"') { - /* JSON string */ - pStream->zText++; - pStr->zString++; - /* Delimit the string */ - while( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '"' && pStream->zText[-1] != '\\' ){ - break; - } - if( pStream->zText[0] == '\n' ){ - /* Update line counter */ - pStream->nLine++; - } - pStream->zText++; - } - if( pStream->zText >= pStream->zEnd ){ - /* Missing closing '"' */ - pToken->nType = JSON_TK_INVALID; - *pJsonErr = SXERR_SYNTAX; - }else{ - pToken->nType = JSON_TK_STR; - pStream->zText++; /* Jump the closing double quotes */ - } - }else if( pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - /* Number */ - pStream->zText++; - pToken->nType = JSON_TK_NUM; - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( c == '.' ){ - /* Real number */ - pStream->zText++; - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( c=='e' || c=='E' ){ - pStream->zText++; - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( c =='+' || c=='-' ){ - pStream->zText++; - } - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - } - } - } - }else if( c=='e' || c=='E' ){ - /* Real number */ - pStream->zText++; - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( c =='+' || c=='-' ){ - pStream->zText++; - } - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - } - } - } - }else{ - /* Unexpected token */ - pToken->nType = JSON_TK_INVALID; - /* Advance the stream cursor */ - pStream->zText++; - *pJsonErr = SXERR_SYNTAX; - /* Abort processing immediatley */ - return SXERR_ABORT; - } - /* record token length */ - pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); - if( pToken->nType == JSON_TK_STR ){ - pStr->nByte--; - } - /* Return to the lexer */ - return SXRET_OK; -} -/* - * JSON decoded input consumer callback signature. - */ -typedef int (*ProcJSONConsumer)(jx9_context *, jx9_value *, jx9_value *, void *); -/* - * JSON decoder state is kept in the following structure. - */ -typedef struct json_decoder json_decoder; -struct json_decoder -{ - jx9_context *pCtx; /* Call context */ - ProcJSONConsumer xConsumer; /* Consumer callback */ - void *pUserData; /* Last argument to xConsumer() */ - int iFlags; /* Configuration flags */ - SyToken *pIn; /* Token stream */ - SyToken *pEnd; /* End of the token stream */ - int rec_count; /* Current nesting level */ - int *pErr; /* JSON decoding error if any */ -}; -/* Forward declaration */ -static int VmJsonArrayDecoder(jx9_context *pCtx, jx9_value *pKey, jx9_value *pWorker, void *pUserData); -/* - * Dequote [i.e: Resolve all backslash escapes ] a JSON string and store - * the result in the given jx9_value. - */ -static void VmJsonDequoteString(const SyString *pStr, jx9_value *pWorker) -{ - const char *zIn = pStr->zString; - const char *zEnd = &pStr->zString[pStr->nByte]; - const char *zCur; - int c; - /* Mark the value as a string */ - jx9_value_string(pWorker, "", 0); /* Empty string */ - for(;;){ - zCur = zIn; - while( zIn < zEnd && zIn[0] != '\\' ){ - zIn++; - } - if( zIn > zCur ){ - /* Append chunk verbatim */ - jx9_value_string(pWorker, zCur, (int)(zIn-zCur)); - } - zIn++; - if( zIn >= zEnd ){ - /* End of the input reached */ - break; - } - c = zIn[0]; - /* Unescape the character */ - switch(c){ - case '"': jx9_value_string(pWorker, (const char *)&c, (int)sizeof(char)); break; - case '\\': jx9_value_string(pWorker, (const char *)&c, (int)sizeof(char)); break; - case 'n': jx9_value_string(pWorker, "\n", (int)sizeof(char)); break; - case 'r': jx9_value_string(pWorker, "\r", (int)sizeof(char)); break; - case 't': jx9_value_string(pWorker, "\t", (int)sizeof(char)); break; - case 'f': jx9_value_string(pWorker, "\f", (int)sizeof(char)); break; - default: - jx9_value_string(pWorker, (const char *)&c, (int)sizeof(char)); - break; - } - /* Advance the stream cursor */ - zIn++; - } -} -/* - * Returns a jx9_value holding the image of a JSON string. In other word perform a JSON decoding operation. - * According to wikipedia - * JSON's basic types are: - * Number (double precision floating-point format in JavaScript, generally depends on implementation) - * String (double-quoted Unicode, with backslash escaping) - * Boolean (true or false) - * Array (an ordered sequence of values, comma-separated and enclosed in square brackets; the values - * do not need to be of the same type) - * Object (an unordered collection of key:value pairs with the ':' character separating the key - * and the value, comma-separated and enclosed in curly braces; the keys must be strings and should - * be distinct from each other) - * null (empty) - * Non-significant white space may be added freely around the "structural characters" (i.e. the brackets "[{]}", colon ":" and comma ", "). - */ -static sxi32 VmJsonDecode( - json_decoder *pDecoder, /* JSON decoder */ - jx9_value *pArrayKey /* Key for the decoded array */ - ){ - jx9_value *pWorker; /* Worker variable */ - sxi32 rc; - /* Check if we do not nest to much */ - if( pDecoder->rec_count > 31 ){ - /* Nesting limit reached, abort decoding immediately */ - return SXERR_ABORT; - } - if( pDecoder->pIn->nType & (JSON_TK_STR|JSON_TK_ID|JSON_TK_TRUE|JSON_TK_FALSE|JSON_TK_NULL|JSON_TK_NUM) ){ - /* Scalar value */ - pWorker = jx9_context_new_scalar(pDecoder->pCtx); - if( pWorker == 0 ){ - jx9_context_throw_error(pDecoder->pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - /* Abort the decoding operation immediately */ - return SXERR_ABORT; - } - /* Reflect the JSON image */ - if( pDecoder->pIn->nType & JSON_TK_NULL ){ - /* Nullify the value.*/ - jx9_value_null(pWorker); - }else if( pDecoder->pIn->nType & (JSON_TK_TRUE|JSON_TK_FALSE) ){ - /* Boolean value */ - jx9_value_bool(pWorker, (pDecoder->pIn->nType & JSON_TK_TRUE) ? 1 : 0 ); - }else if( pDecoder->pIn->nType & JSON_TK_NUM ){ - SyString *pStr = &pDecoder->pIn->sData; - /* - * Numeric value. - * Get a string representation first then try to get a numeric - * value. - */ - jx9_value_string(pWorker, pStr->zString, (int)pStr->nByte); - /* Obtain a numeric representation */ - jx9MemObjToNumeric(pWorker); - }else if( pDecoder->pIn->nType & JSON_TK_ID ){ - SyString *pStr = &pDecoder->pIn->sData; - jx9_value_string(pWorker, pStr->zString, (int)pStr->nByte); - }else{ - /* Dequote the string */ - VmJsonDequoteString(&pDecoder->pIn->sData, pWorker); - } - /* Invoke the consumer callback */ - rc = pDecoder->xConsumer(pDecoder->pCtx, pArrayKey, pWorker, pDecoder->pUserData); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - /* All done, advance the stream cursor */ - pDecoder->pIn++; - }else if( pDecoder->pIn->nType & JSON_TK_OSB /*'[' */) { - ProcJSONConsumer xOld; - void *pOld; - /* Array representation*/ - pDecoder->pIn++; - /* Create a working array */ - pWorker = jx9_context_new_array(pDecoder->pCtx); - if( pWorker == 0 ){ - jx9_context_throw_error(pDecoder->pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - /* Abort the decoding operation immediately */ - return SXERR_ABORT; - } - /* Save the old consumer */ - xOld = pDecoder->xConsumer; - pOld = pDecoder->pUserData; - /* Set the new consumer */ - pDecoder->xConsumer = VmJsonArrayDecoder; - pDecoder->pUserData = pWorker; - /* Decode the array */ - for(;;){ - /* Jump trailing comma. Note that the standard JX9 engine will not let you - * do this. - */ - while( (pDecoder->pIn < pDecoder->pEnd) && (pDecoder->pIn->nType & JSON_TK_COMMA) ){ - pDecoder->pIn++; - } - if( pDecoder->pIn >= pDecoder->pEnd || (pDecoder->pIn->nType & JSON_TK_CSB) /*']'*/ ){ - if( pDecoder->pIn < pDecoder->pEnd ){ - pDecoder->pIn++; /* Jump the trailing ']' */ - } - break; - } - /* Recurse and decode the entry */ - pDecoder->rec_count++; - rc = VmJsonDecode(pDecoder, 0); - pDecoder->rec_count--; - if( rc == SXERR_ABORT ){ - /* Abort processing immediately */ - return SXERR_ABORT; - } - /*The cursor is automatically advanced by the VmJsonDecode() function */ - if( (pDecoder->pIn < pDecoder->pEnd) && - ((pDecoder->pIn->nType & (JSON_TK_CSB/*']'*/|JSON_TK_COMMA/*','*/))==0) ){ - /* Unexpected token, abort immediatley */ - *pDecoder->pErr = SXERR_SYNTAX; - return SXERR_ABORT; - } - } - /* Restore the old consumer */ - pDecoder->xConsumer = xOld; - pDecoder->pUserData = pOld; - /* Invoke the old consumer on the decoded array */ - xOld(pDecoder->pCtx, pArrayKey, pWorker, pOld); - }else if( pDecoder->pIn->nType & JSON_TK_OCB /*'{' */) { - ProcJSONConsumer xOld; - jx9_value *pKey; - void *pOld; - /* Object representation*/ - pDecoder->pIn++; - /* Create a working array */ - pWorker = jx9_context_new_array(pDecoder->pCtx); - pKey = jx9_context_new_scalar(pDecoder->pCtx); - if( pWorker == 0 || pKey == 0){ - jx9_context_throw_error(pDecoder->pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - /* Abort the decoding operation immediately */ - return SXERR_ABORT; - } - /* Save the old consumer */ - xOld = pDecoder->xConsumer; - pOld = pDecoder->pUserData; - /* Set the new consumer */ - pDecoder->xConsumer = VmJsonArrayDecoder; - pDecoder->pUserData = pWorker; - /* Decode the object */ - for(;;){ - /* Jump trailing comma. Note that the standard JX9 engine will not let you - * do this. - */ - while( (pDecoder->pIn < pDecoder->pEnd) && (pDecoder->pIn->nType & JSON_TK_COMMA) ){ - pDecoder->pIn++; - } - if( pDecoder->pIn >= pDecoder->pEnd || (pDecoder->pIn->nType & JSON_TK_CCB) /*'}'*/ ){ - if( pDecoder->pIn < pDecoder->pEnd ){ - pDecoder->pIn++; /* Jump the trailing ']' */ - } - break; - } - if( (pDecoder->pIn->nType & (JSON_TK_ID|JSON_TK_STR)) == 0 || &pDecoder->pIn[1] >= pDecoder->pEnd - || (pDecoder->pIn[1].nType & JSON_TK_COLON) == 0){ - /* Syntax error, return immediately */ - *pDecoder->pErr = SXERR_SYNTAX; - return SXERR_ABORT; - } - if( pDecoder->pIn->nType & JSON_TK_ID ){ - SyString *pStr = &pDecoder->pIn->sData; - jx9_value_string(pKey, pStr->zString, (int)pStr->nByte); - }else{ - /* Dequote the key */ - VmJsonDequoteString(&pDecoder->pIn->sData, pKey); - } - /* Jump the key and the colon */ - pDecoder->pIn += 2; - /* Recurse and decode the value */ - pDecoder->rec_count++; - rc = VmJsonDecode(pDecoder, pKey); - pDecoder->rec_count--; - if( rc == SXERR_ABORT ){ - /* Abort processing immediately */ - return SXERR_ABORT; - } - /* Reset the internal buffer of the key */ - jx9_value_reset_string_cursor(pKey); - /*The cursor is automatically advanced by the VmJsonDecode() function */ - } - /* Restore the old consumer */ - pDecoder->xConsumer = xOld; - pDecoder->pUserData = pOld; - /* Invoke the old consumer on the decoded object*/ - xOld(pDecoder->pCtx, pArrayKey, pWorker, pOld); - /* Release the key */ - jx9_context_release_value(pDecoder->pCtx, pKey); - }else{ - /* Unexpected token */ - return SXERR_ABORT; /* Abort immediately */ - } - /* Release the worker variable */ - jx9_context_release_value(pDecoder->pCtx, pWorker); - return SXRET_OK; -} -/* - * The following JSON decoder callback is invoked each time - * a JSON array representation [i.e: [15, "hello", FALSE] ] - * is being decoded. - */ -static int VmJsonArrayDecoder(jx9_context *pCtx, jx9_value *pKey, jx9_value *pWorker, void *pUserData) -{ - jx9_value *pArray = (jx9_value *)pUserData; - /* Insert the entry */ - jx9_array_add_elem(pArray, pKey, pWorker); /* Will make it's own copy */ - SXUNUSED(pCtx); /* cc warning */ - /* All done */ - return SXRET_OK; -} -/* - * Standard JSON decoder callback. - */ -static int VmJsonDefaultDecoder(jx9_context *pCtx, jx9_value *pKey, jx9_value *pWorker, void *pUserData) -{ - /* Return the value directly */ - jx9_result_value(pCtx, pWorker); /* Will make it's own copy */ - SXUNUSED(pKey); /* cc warning */ - SXUNUSED(pUserData); - /* All done */ - return SXRET_OK; -} -/* - * Exported JSON decoding interface - */ -JX9_PRIVATE int jx9JsonDecode(jx9_context *pCtx,const char *zJSON,int nByte) -{ - jx9_vm *pVm = pCtx->pVm; - json_decoder sDecoder; - SySet sToken; - SyLex sLex; - sxi32 rc; - /* Tokenize the input */ - SySetInit(&sToken, &pVm->sAllocator, sizeof(SyToken)); - rc = SXRET_OK; - SyLexInit(&sLex, &sToken, VmJsonTokenize, &rc); - SyLexTokenizeInput(&sLex,zJSON,(sxu32)nByte, 0, 0, 0); - if( rc != SXRET_OK ){ - /* Something goes wrong while tokenizing input. [i.e: Unexpected token] */ - SyLexRelease(&sLex); - SySetRelease(&sToken); - /* return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Fill the decoder */ - sDecoder.pCtx = pCtx; - sDecoder.pErr = &rc; - sDecoder.pIn = (SyToken *)SySetBasePtr(&sToken); - sDecoder.pEnd = &sDecoder.pIn[SySetUsed(&sToken)]; - sDecoder.iFlags = 0; - sDecoder.rec_count = 0; - /* Set a default consumer */ - sDecoder.xConsumer = VmJsonDefaultDecoder; - sDecoder.pUserData = 0; - /* Decode the raw JSON input */ - rc = VmJsonDecode(&sDecoder, 0); - if( rc == SXERR_ABORT ){ - /* - * Something goes wrong while decoding JSON input.Return NULL. - */ - jx9_result_null(pCtx); - } - /* Clean-up the mess left behind */ - SyLexRelease(&sLex); - SySetRelease(&sToken); - /* All done */ - return JX9_OK; -} -/* - * ---------------------------------------------------------- - * File: jx9_lex.c - * MD5: a79518c0635dbaf5dcfaca62efa2faf8 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: lex.c v1.0 FreeBSD 2012-12-09 00:19 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* This file implements a thread-safe and full reentrant lexical analyzer for the Jx9 programming language */ -/* Forward declarations */ -static sxu32 keywordCode(const char *z,int n); -static sxi32 LexExtractNowdoc(SyStream *pStream,SyToken *pToken); -/* - * Tokenize a raw jx9 input. - * Get a single low-level token from the input file. Update the stream pointer so that - * it points to the first character beyond the extracted token. - */ -static sxi32 jx9TokenizeInput(SyStream *pStream,SyToken *pToken,void *pUserData,void *pCtxData) -{ - SyString *pStr; - sxi32 rc; - /* Ignore leading white spaces */ - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisSpace(pStream->zText[0]) ){ - /* Advance the stream cursor */ - if( pStream->zText[0] == '\n' ){ - /* Update line counter */ - pStream->nLine++; - } - pStream->zText++; - } - if( pStream->zText >= pStream->zEnd ){ - /* End of input reached */ - return SXERR_EOF; - } - /* Record token starting position and line */ - pToken->nLine = pStream->nLine; - pToken->pUserData = 0; - pStr = &pToken->sData; - SyStringInitFromBuf(pStr, pStream->zText, 0); - if( pStream->zText[0] >= 0xc0 || SyisAlpha(pStream->zText[0]) || pStream->zText[0] == '_' ){ - /* The following code fragment is taken verbatim from the xPP source tree. - * xPP is a modern embeddable macro processor with advanced features useful for - * application seeking for a production quality, ready to use macro processor. - * xPP is a widely used library developed and maintened by Symisc Systems. - * You can reach the xPP home page by following this link: - * http://xpp.symisc.net/ - */ - const unsigned char *zIn; - sxu32 nKeyword; - /* Isolate UTF-8 or alphanumeric stream */ - if( pStream->zText[0] < 0xc0 ){ - pStream->zText++; - } - for(;;){ - zIn = pStream->zText; - if( zIn[0] >= 0xc0 ){ - zIn++; - /* UTF-8 stream */ - while( zIn < pStream->zEnd && ((zIn[0] & 0xc0) == 0x80) ){ - zIn++; - } - } - /* Skip alphanumeric stream */ - while( zIn < pStream->zEnd && zIn[0] < 0xc0 && (SyisAlphaNum(zIn[0]) || zIn[0] == '_') ){ - zIn++; - } - if( zIn == pStream->zText ){ - /* Not an UTF-8 or alphanumeric stream */ - break; - } - /* Synchronize pointers */ - pStream->zText = zIn; - } - /* Record token length */ - pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); - nKeyword = keywordCode(pStr->zString, (int)pStr->nByte); - if( nKeyword != JX9_TK_ID ){ - /* We are dealing with a keyword [i.e: if, function, CREATE, ...], save the keyword ID */ - pToken->nType = JX9_TK_KEYWORD; - pToken->pUserData = SX_INT_TO_PTR(nKeyword); - }else{ - /* A simple identifier */ - pToken->nType = JX9_TK_ID; - } - }else{ - sxi32 c; - /* Non-alpha stream */ - if( pStream->zText[0] == '#' || - ( pStream->zText[0] == '/' && &pStream->zText[1] < pStream->zEnd && pStream->zText[1] == '/') ){ - pStream->zText++; - /* Inline comments */ - while( pStream->zText < pStream->zEnd && pStream->zText[0] != '\n' ){ - pStream->zText++; - } - /* Tell the upper-layer to ignore this token */ - return SXERR_CONTINUE; - }else if( pStream->zText[0] == '/' && &pStream->zText[1] < pStream->zEnd && pStream->zText[1] == '*' ){ - pStream->zText += 2; - /* Block comment */ - while( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '*' ){ - if( &pStream->zText[1] >= pStream->zEnd || pStream->zText[1] == '/' ){ - break; - } - } - if( pStream->zText[0] == '\n' ){ - pStream->nLine++; - } - pStream->zText++; - } - pStream->zText += 2; - /* Tell the upper-layer to ignore this token */ - return SXERR_CONTINUE; - }else if( SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - /* Decimal digit stream */ - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - /* Mark the token as integer until we encounter a real number */ - pToken->nType = JX9_TK_INTEGER; - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( c == '.' ){ - /* Real number */ - pStream->zText++; - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( c=='e' || c=='E' ){ - pStream->zText++; - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( (c =='+' || c=='-') && &pStream->zText[1] < pStream->zEnd && - pStream->zText[1] < 0xc0 && SyisDigit(pStream->zText[1]) ){ - pStream->zText++; - } - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - } - } - } - pToken->nType = JX9_TK_REAL; - }else if( c=='e' || c=='E' ){ - SXUNUSED(pUserData); /* Prevent compiler warning */ - SXUNUSED(pCtxData); - pStream->zText++; - if( pStream->zText < pStream->zEnd ){ - c = pStream->zText[0]; - if( (c =='+' || c=='-') && &pStream->zText[1] < pStream->zEnd && - pStream->zText[1] < 0xc0 && SyisDigit(pStream->zText[1]) ){ - pStream->zText++; - } - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisDigit(pStream->zText[0]) ){ - pStream->zText++; - } - } - pToken->nType = JX9_TK_REAL; - }else if( c == 'x' || c == 'X' ){ - /* Hex digit stream */ - pStream->zText++; - while( pStream->zText < pStream->zEnd && pStream->zText[0] < 0xc0 && SyisHex(pStream->zText[0]) ){ - pStream->zText++; - } - }else if(c == 'b' || c == 'B' ){ - /* Binary digit stream */ - pStream->zText++; - while( pStream->zText < pStream->zEnd && (pStream->zText[0] == '0' || pStream->zText[0] == '1') ){ - pStream->zText++; - } - } - } - /* Record token length */ - pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); - return SXRET_OK; - } - c = pStream->zText[0]; - pStream->zText++; /* Advance the stream cursor */ - /* Assume we are dealing with an operator*/ - pToken->nType = JX9_TK_OP; - switch(c){ - case '$': pToken->nType = JX9_TK_DOLLAR; break; - case '{': pToken->nType = JX9_TK_OCB; break; - case '}': pToken->nType = JX9_TK_CCB; break; - case '(': pToken->nType = JX9_TK_LPAREN; break; - case '[': pToken->nType |= JX9_TK_OSB; break; /* Bitwise operation here, since the square bracket token '[' - * is a potential operator [i.e: subscripting] */ - case ']': pToken->nType = JX9_TK_CSB; break; - case ')': { - SySet *pTokSet = pStream->pSet; - /* Assemble type cast operators [i.e: (int), (float), (bool)...] */ - if( pTokSet->nUsed >= 2 ){ - SyToken *pTmp; - /* Peek the last recongnized token */ - pTmp = (SyToken *)SySetPeek(pTokSet); - if( pTmp->nType & JX9_TK_KEYWORD ){ - sxi32 nID = SX_PTR_TO_INT(pTmp->pUserData); - if( (sxu32)nID & (JX9_TKWRD_INT|JX9_TKWRD_FLOAT|JX9_TKWRD_STRING|JX9_TKWRD_BOOL) ){ - pTmp = (SyToken *)SySetAt(pTokSet, pTokSet->nUsed - 2); - if( pTmp->nType & JX9_TK_LPAREN ){ - /* Merge the three tokens '(' 'TYPE' ')' into a single one */ - const char * zTypeCast = "(int)"; - if( nID & JX9_TKWRD_FLOAT ){ - zTypeCast = "(float)"; - }else if( nID & JX9_TKWRD_BOOL ){ - zTypeCast = "(bool)"; - }else if( nID & JX9_TKWRD_STRING ){ - zTypeCast = "(string)"; - } - /* Reflect the change */ - pToken->nType = JX9_TK_OP; - SyStringInitFromBuf(&pToken->sData, zTypeCast, SyStrlen(zTypeCast)); - /* Save the instance associated with the type cast operator */ - pToken->pUserData = (void *)jx9ExprExtractOperator(&pToken->sData, 0); - /* Remove the two previous tokens */ - pTokSet->nUsed -= 2; - return SXRET_OK; - } - } - } - } - pToken->nType = JX9_TK_RPAREN; - break; - } - case '\'':{ - /* Single quoted string */ - pStr->zString++; - while( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '\'' ){ - if( pStream->zText[-1] != '\\' ){ - break; - }else{ - const unsigned char *zPtr = &pStream->zText[-2]; - sxi32 i = 1; - while( zPtr > pStream->zInput && zPtr[0] == '\\' ){ - zPtr--; - i++; - } - if((i&1)==0){ - break; - } - } - } - if( pStream->zText[0] == '\n' ){ - pStream->nLine++; - } - pStream->zText++; - } - /* Record token length and type */ - pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); - pToken->nType = JX9_TK_SSTR; - /* Jump the trailing single quote */ - pStream->zText++; - return SXRET_OK; - } - case '"':{ - sxi32 iNest; - /* Double quoted string */ - pStr->zString++; - while( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '{' && &pStream->zText[1] < pStream->zEnd && pStream->zText[1] == '$'){ - iNest = 1; - pStream->zText++; - /* TICKET 1433-40: Hnadle braces'{}' in double quoted string where everything is allowed */ - while(pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '{' ){ - iNest++; - }else if (pStream->zText[0] == '}' ){ - iNest--; - if( iNest <= 0 ){ - pStream->zText++; - break; - } - }else if( pStream->zText[0] == '\n' ){ - pStream->nLine++; - } - pStream->zText++; - } - if( pStream->zText >= pStream->zEnd ){ - break; - } - } - if( pStream->zText[0] == '"' ){ - if( pStream->zText[-1] != '\\' ){ - break; - }else{ - const unsigned char *zPtr = &pStream->zText[-2]; - sxi32 i = 1; - while( zPtr > pStream->zInput && zPtr[0] == '\\' ){ - zPtr--; - i++; - } - if((i&1)==0){ - break; - } - } - } - if( pStream->zText[0] == '\n' ){ - pStream->nLine++; - } - pStream->zText++; - } - /* Record token length and type */ - pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); - pToken->nType = JX9_TK_DSTR; - /* Jump the trailing quote */ - pStream->zText++; - return SXRET_OK; - } - case ':': - pToken->nType = JX9_TK_COLON; /* Single colon */ - break; - case ',': pToken->nType |= JX9_TK_COMMA; break; /* Comma is also an operator */ - case ';': pToken->nType = JX9_TK_SEMI; break; - /* Handle combined operators [i.e: +=, ===, !=== ...] */ - case '=': - pToken->nType |= JX9_TK_EQUAL; - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '=' ){ - pToken->nType &= ~JX9_TK_EQUAL; - /* Current operator: == */ - pStream->zText++; - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: === */ - pStream->zText++; - } - } - } - break; - case '!': - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: != */ - pStream->zText++; - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: !== */ - pStream->zText++; - } - } - break; - case '&': - pToken->nType |= JX9_TK_AMPER; - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '&' ){ - pToken->nType &= ~JX9_TK_AMPER; - /* Current operator: && */ - pStream->zText++; - }else if( pStream->zText[0] == '=' ){ - pToken->nType &= ~JX9_TK_AMPER; - /* Current operator: &= */ - pStream->zText++; - } - } - case '.': - if( pStream->zText < pStream->zEnd && (pStream->zText[0] == '.' || pStream->zText[0] == '=') ){ - /* Concatenation operator: '..' or '.=' */ - pStream->zText++; - } - break; - case '|': - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '|' ){ - /* Current operator: || */ - pStream->zText++; - }else if( pStream->zText[0] == '=' ){ - /* Current operator: |= */ - pStream->zText++; - } - } - break; - case '+': - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '+' ){ - /* Current operator: ++ */ - pStream->zText++; - }else if( pStream->zText[0] == '=' ){ - /* Current operator: += */ - pStream->zText++; - } - } - break; - case '-': - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '-' ){ - /* Current operator: -- */ - pStream->zText++; - }else if( pStream->zText[0] == '=' ){ - /* Current operator: -= */ - pStream->zText++; - }else if( pStream->zText[0] == '>' ){ - /* Current operator: -> */ - pStream->zText++; - } - } - break; - case '*': - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: *= */ - pStream->zText++; - } - break; - case '/': - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: /= */ - pStream->zText++; - } - break; - case '%': - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: %= */ - pStream->zText++; - } - break; - case '^': - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: ^= */ - pStream->zText++; - } - break; - case '<': - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '<' ){ - /* Current operator: << */ - pStream->zText++; - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '=' ){ - /* Current operator: <<= */ - pStream->zText++; - }else if( pStream->zText[0] == '<' ){ - /* Current Token: <<< */ - pStream->zText++; - /* This may be the beginning of a Heredoc/Nowdoc string, try to delimit it */ - rc = LexExtractNowdoc(&(*pStream), &(*pToken)); - if( rc == SXRET_OK ){ - /* Here/Now doc successfuly extracted */ - return SXRET_OK; - } - } - } - }else if( pStream->zText[0] == '>' ){ - /* Current operator: <> */ - pStream->zText++; - }else if( pStream->zText[0] == '=' ){ - /* Current operator: <= */ - pStream->zText++; - } - } - break; - case '>': - if( pStream->zText < pStream->zEnd ){ - if( pStream->zText[0] == '>' ){ - /* Current operator: >> */ - pStream->zText++; - if( pStream->zText < pStream->zEnd && pStream->zText[0] == '=' ){ - /* Current operator: >>= */ - pStream->zText++; - } - }else if( pStream->zText[0] == '=' ){ - /* Current operator: >= */ - pStream->zText++; - } - } - break; - default: - break; - } - if( pStr->nByte <= 0 ){ - /* Record token length */ - pStr->nByte = (sxu32)((const char *)pStream->zText-pStr->zString); - } - if( pToken->nType & JX9_TK_OP ){ - const jx9_expr_op *pOp; - /* Check if the extracted token is an operator */ - pOp = jx9ExprExtractOperator(pStr, (SyToken *)SySetPeek(pStream->pSet)); - if( pOp == 0 ){ - /* Not an operator */ - pToken->nType &= ~JX9_TK_OP; - if( pToken->nType <= 0 ){ - pToken->nType = JX9_TK_OTHER; - } - }else{ - /* Save the instance associated with this operator for later processing */ - pToken->pUserData = (void *)pOp; - } - } - } - /* Tell the upper-layer to save the extracted token for later processing */ - return SXRET_OK; -} -/***** This file contains automatically generated code ****** -** -** The code in this file has been automatically generated by -** -** $Header: /sqlite/sqlite/tool/mkkeywordhash.c,v 1.38 2011/12/21 01:00:46 $ -** -** The code in this file implements a function that determines whether -** or not a given identifier is really a JX9 keyword. The same thing -** might be implemented more directly using a hand-written hash table. -** But by using this automatically generated code, the size of the code -** is substantially reduced. This is important for embedded applications -** on platforms with limited memory. -*/ -/* Hash score: 35 */ -static sxu32 keywordCode(const char *z, int n) -{ - /* zText[] encodes 188 bytes of keywords in 128 bytes */ - /* printegereturnconstaticaselseifloatincludefaultDIEXITcontinue */ - /* diewhileASPRINTbooleanbreakforeachfunctionimportstringswitch */ - /* uplink */ - static const char zText[127] = { - 'p','r','i','n','t','e','g','e','r','e','t','u','r','n','c','o','n','s', - 't','a','t','i','c','a','s','e','l','s','e','i','f','l','o','a','t','i', - 'n','c','l','u','d','e','f','a','u','l','t','D','I','E','X','I','T','c', - 'o','n','t','i','n','u','e','d','i','e','w','h','i','l','e','A','S','P', - 'R','I','N','T','b','o','o','l','e','a','n','b','r','e','a','k','f','o', - 'r','e','a','c','h','f','u','n','c','t','i','o','n','i','m','p','o','r', - 't','s','t','r','i','n','g','s','w','i','t','c','h','u','p','l','i','n', - 'k', - }; - static const unsigned char aHash[59] = { - 0, 0, 0, 0, 15, 0, 30, 0, 0, 2, 19, 18, 0, - 0, 10, 3, 12, 0, 28, 29, 23, 0, 13, 22, 0, 0, - 14, 24, 25, 31, 11, 0, 0, 0, 0, 1, 5, 0, 0, - 20, 0, 27, 9, 0, 0, 0, 8, 0, 0, 26, 6, 0, - 0, 17, 0, 0, 0, 0, 0, - }; - static const unsigned char aNext[31] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 21, 7, - 0, 0, 0, 0, 0, - }; - static const unsigned char aLen[31] = { - 5, 7, 3, 6, 5, 6, 4, 2, 6, 4, 2, 5, 7, - 7, 3, 4, 8, 3, 5, 2, 5, 4, 7, 5, 3, 7, - 8, 6, 6, 6, 6, - }; - static const sxu16 aOffset[31] = { - 0, 2, 2, 8, 14, 17, 22, 23, 25, 25, 29, 30, 35, - 40, 47, 49, 53, 61, 64, 69, 71, 76, 76, 83, 88, 88, - 95, 103, 109, 115, 121, - }; - static const sxu32 aCode[31] = { - JX9_TKWRD_PRINT, JX9_TKWRD_INT, JX9_TKWRD_INT, JX9_TKWRD_RETURN, JX9_TKWRD_CONST, - JX9_TKWRD_STATIC, JX9_TKWRD_CASE, JX9_TKWRD_AS, JX9_TKWRD_ELIF, JX9_TKWRD_ELSE, - JX9_TKWRD_IF, JX9_TKWRD_FLOAT, JX9_TKWRD_INCLUDE, JX9_TKWRD_DEFAULT, JX9_TKWRD_DIE, - JX9_TKWRD_EXIT, JX9_TKWRD_CONTINUE, JX9_TKWRD_DIE, JX9_TKWRD_WHILE, JX9_TKWRD_AS, - JX9_TKWRD_PRINT, JX9_TKWRD_BOOL, JX9_TKWRD_BOOL, JX9_TKWRD_BREAK, JX9_TKWRD_FOR, - JX9_TKWRD_FOREACH, JX9_TKWRD_FUNCTION, JX9_TKWRD_IMPORT, JX9_TKWRD_STRING, JX9_TKWRD_SWITCH, - JX9_TKWRD_UPLINK, - }; - int h, i; - if( n<2 ) return JX9_TK_ID; - h = (((int)z[0]*4) ^ ((int)z[n-1]*3) ^ n) % 59; - for(i=((int)aHash[h])-1; i>=0; i=((int)aNext[i])-1){ - if( (int)aLen[i]==n && SyMemcmp(&zText[aOffset[i]],z,n)==0 ){ - /* JX9_TKWRD_PRINT */ - /* JX9_TKWRD_INT */ - /* JX9_TKWRD_INT */ - /* JX9_TKWRD_RETURN */ - /* JX9_TKWRD_CONST */ - /* JX9_TKWRD_STATIC */ - /* JX9_TKWRD_CASE */ - /* JX9_TKWRD_AS */ - /* JX9_TKWRD_ELIF */ - /* JX9_TKWRD_ELSE */ - /* JX9_TKWRD_IF */ - /* JX9_TKWRD_FLOAT */ - /* JX9_TKWRD_INCLUDE */ - /* JX9_TKWRD_DEFAULT */ - /* JX9_TKWRD_DIE */ - /* JX9_TKWRD_EXIT */ - /* JX9_TKWRD_CONTINUE */ - /* JX9_TKWRD_DIE */ - /* JX9_TKWRD_WHILE */ - /* JX9_TKWRD_AS */ - /* JX9_TKWRD_PRINT */ - /* JX9_TKWRD_BOOL */ - /* JX9_TKWRD_BOOL */ - /* JX9_TKWRD_BREAK */ - /* JX9_TKWRD_FOR */ - /* JX9_TKWRD_FOREACH */ - /* JX9_TKWRD_FUNCTION */ - /* JX9_TKWRD_IMPORT */ - /* JX9_TKWRD_STRING */ - /* JX9_TKWRD_SWITCH */ - /* JX9_TKWRD_UPLINK */ - return aCode[i]; - } - } - return JX9_TK_ID; -} -/* - * Extract a heredoc/nowdoc text from a raw JX9 input. - * According to the JX9 language reference manual: - * A third way to delimit strings is the heredoc syntax: <<<. After this operator, an identifier - * is provided, then a newline. The string itself follows, and then the same identifier again - * to close the quotation. - * The closing identifier must begin in the first column of the line. Also, the identifier must - * follow the same naming rules as any other label in JX9: it must contain only alphanumeric - * characters and underscores, and must start with a non-digit character or underscore. - * Heredoc text behaves just like a double-quoted string, without the double quotes. - * This means that quotes in a heredoc do not need to be escaped, but the escape codes listed - * above can still be used. Variables are expanded, but the same care must be taken when expressing - * complex variables inside a heredoc as with strings. - * Nowdocs are to single-quoted strings what heredocs are to double-quoted strings. - * A nowdoc is specified similarly to a heredoc, but no parsing is done inside a nowdoc. - * The construct is ideal for embedding JX9 code or other large blocks of text without the need - * for escaping. It shares some features in common with the SGML construct, in that - * it declares a block of text which is not for parsing. - * A nowdoc is identified with the same <<< sequence used for heredocs, but the identifier which follows - * is enclosed in single quotes, e.g. <<<'EOT'. All the rules for heredoc identifiers also apply to nowdoc - * identifiers, especially those regarding the appearance of the closing identifier. - */ -static sxi32 LexExtractNowdoc(SyStream *pStream, SyToken *pToken) -{ - const unsigned char *zIn = pStream->zText; - const unsigned char *zEnd = pStream->zEnd; - const unsigned char *zPtr; - SyString sDelim; - SyString sStr; - /* Jump leading white spaces */ - while( zIn < zEnd && zIn[0] < 0xc0 && SyisSpace(zIn[0]) && zIn[0] != '\n' ){ - zIn++; - } - if( zIn >= zEnd ){ - /* A simple symbol, return immediately */ - return SXERR_CONTINUE; - } - if( zIn[0] == '\'' || zIn[0] == '"' ){ - zIn++; - } - if( zIn[0] < 0xc0 && !SyisAlphaNum(zIn[0]) && zIn[0] != '_' ){ - /* Invalid delimiter, return immediately */ - return SXERR_CONTINUE; - } - /* Isolate the identifier */ - sDelim.zString = (const char *)zIn; - for(;;){ - zPtr = zIn; - /* Skip alphanumeric stream */ - while( zPtr < zEnd && zPtr[0] < 0xc0 && (SyisAlphaNum(zPtr[0]) || zPtr[0] == '_') ){ - zPtr++; - } - if( zPtr < zEnd && zPtr[0] >= 0xc0 ){ - zPtr++; - /* UTF-8 stream */ - while( zPtr < zEnd && ((zPtr[0] & 0xc0) == 0x80) ){ - zPtr++; - } - } - if( zPtr == zIn ){ - /* Not an UTF-8 or alphanumeric stream */ - break; - } - /* Synchronize pointers */ - zIn = zPtr; - } - /* Get the identifier length */ - sDelim.nByte = (sxu32)((const char *)zIn-sDelim.zString); - if( zIn[0] == '"' || zIn[0] == '\'' ){ - /* Jump the trailing single quote */ - zIn++; - } - /* Jump trailing white spaces */ - while( zIn < zEnd && zIn[0] < 0xc0 && SyisSpace(zIn[0]) && zIn[0] != '\n' ){ - zIn++; - } - if( sDelim.nByte <= 0 || zIn >= zEnd || zIn[0] != '\n' ){ - /* Invalid syntax */ - return SXERR_CONTINUE; - } - pStream->nLine++; /* Increment line counter */ - zIn++; - /* Isolate the delimited string */ - sStr.zString = (const char *)zIn; - /* Go and found the closing delimiter */ - for(;;){ - /* Synchronize with the next line */ - while( zIn < zEnd && zIn[0] != '\n' ){ - zIn++; - } - if( zIn >= zEnd ){ - /* End of the input reached, break immediately */ - pStream->zText = pStream->zEnd; - break; - } - pStream->nLine++; /* Increment line counter */ - zIn++; - if( (sxu32)(zEnd - zIn) >= sDelim.nByte && SyMemcmp((const void *)sDelim.zString, (const void *)zIn, sDelim.nByte) == 0 ){ - zPtr = &zIn[sDelim.nByte]; - while( zPtr < zEnd && zPtr[0] < 0xc0 && SyisSpace(zPtr[0]) && zPtr[0] != '\n' ){ - zPtr++; - } - if( zPtr >= zEnd ){ - /* End of input */ - pStream->zText = zPtr; - break; - } - if( zPtr[0] == ';' ){ - const unsigned char *zCur = zPtr; - zPtr++; - while( zPtr < zEnd && zPtr[0] < 0xc0 && SyisSpace(zPtr[0]) && zPtr[0] != '\n' ){ - zPtr++; - } - if( zPtr >= zEnd || zPtr[0] == '\n' ){ - /* Closing delimiter found, break immediately */ - pStream->zText = zCur; /* Keep the semi-colon */ - break; - } - }else if( zPtr[0] == '\n' ){ - /* Closing delimiter found, break immediately */ - pStream->zText = zPtr; /* Synchronize with the stream cursor */ - break; - } - /* Synchronize pointers and continue searching */ - zIn = zPtr; - } - } /* For(;;) */ - /* Get the delimited string length */ - sStr.nByte = (sxu32)((const char *)zIn-sStr.zString); - /* Record token type and length */ - pToken->nType = JX9_TK_NOWDOC; - SyStringDupPtr(&pToken->sData, &sStr); - /* Remove trailing white spaces */ - SyStringRightTrim(&pToken->sData); - /* All done */ - return SXRET_OK; -} -/* - * Tokenize a raw jx9 input. - * This is the public tokenizer called by most code generator routines. - */ -JX9_PRIVATE sxi32 jx9Tokenize(const char *zInput,sxu32 nLen,SySet *pOut) -{ - SyLex sLexer; - sxi32 rc; - /* Initialize the lexer */ - rc = SyLexInit(&sLexer, &(*pOut),jx9TokenizeInput,0); - if( rc != SXRET_OK ){ - return rc; - } - /* Tokenize input */ - rc = SyLexTokenizeInput(&sLexer, zInput, nLen, 0, 0, 0); - /* Release the lexer */ - SyLexRelease(&sLexer); - /* Tokenization result */ - return rc; -} - -/* - * ---------------------------------------------------------- - * File: jx9_lib.c - * MD5: a684fb6677b1ab0110d03536f1280c50 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: lib.c v5.1 Win7 2012-08-08 04:19 stable $ */ -/* - * Symisc Run-Time API: A modern thread safe replacement of the standard libc - * Copyright (C) Symisc Systems 2007-2012, http://www.symisc.net/ - * - * The Symisc Run-Time API is an independent project developed by symisc systems - * internally as a secure replacement of the standard libc. - * The library is re-entrant, thread-safe and platform independent. - */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -#if defined(__WINNT__) -#include -#else -#include -#endif -#if defined(JX9_ENABLE_THREADS) -/* SyRunTimeApi: sxmutex.c */ -#if defined(__WINNT__) -struct SyMutex -{ - CRITICAL_SECTION sMutex; - sxu32 nType; /* Mutex type, one of SXMUTEX_TYPE_* */ -}; -/* Preallocated static mutex */ -static SyMutex aStaticMutexes[] = { - {{0}, SXMUTEX_TYPE_STATIC_1}, - {{0}, SXMUTEX_TYPE_STATIC_2}, - {{0}, SXMUTEX_TYPE_STATIC_3}, - {{0}, SXMUTEX_TYPE_STATIC_4}, - {{0}, SXMUTEX_TYPE_STATIC_5}, - {{0}, SXMUTEX_TYPE_STATIC_6} -}; -static BOOL winMutexInit = FALSE; -static LONG winMutexLock = 0; - -static sxi32 WinMutexGlobaInit(void) -{ - LONG rc; - rc = InterlockedCompareExchange(&winMutexLock, 1, 0); - if ( rc == 0 ){ - sxu32 n; - for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){ - InitializeCriticalSection(&aStaticMutexes[n].sMutex); - } - winMutexInit = TRUE; - }else{ - /* Someone else is doing this for us */ - while( winMutexInit == FALSE ){ - Sleep(1); - } - } - return SXRET_OK; -} -static void WinMutexGlobalRelease(void) -{ - LONG rc; - rc = InterlockedCompareExchange(&winMutexLock, 0, 1); - if( rc == 1 ){ - /* The first to decrement to zero does the actual global release */ - if( winMutexInit == TRUE ){ - sxu32 n; - for( n = 0 ; n < SX_ARRAYSIZE(aStaticMutexes) ; ++n ){ - DeleteCriticalSection(&aStaticMutexes[n].sMutex); - } - winMutexInit = FALSE; - } - } -} -static SyMutex * WinMutexNew(int nType) -{ - SyMutex *pMutex = 0; - if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){ - /* Allocate a new mutex */ - pMutex = (SyMutex *)HeapAlloc(GetProcessHeap(), 0, sizeof(SyMutex)); - if( pMutex == 0 ){ - return 0; - } - InitializeCriticalSection(&pMutex->sMutex); - }else{ - /* Use a pre-allocated static mutex */ - if( nType > SXMUTEX_TYPE_STATIC_6 ){ - nType = SXMUTEX_TYPE_STATIC_6; - } - pMutex = &aStaticMutexes[nType - 3]; - } - pMutex->nType = nType; - return pMutex; -} -static void WinMutexRelease(SyMutex *pMutex) -{ - if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){ - DeleteCriticalSection(&pMutex->sMutex); - HeapFree(GetProcessHeap(), 0, pMutex); - } -} -static void WinMutexEnter(SyMutex *pMutex) -{ - EnterCriticalSection(&pMutex->sMutex); -} -static sxi32 WinMutexTryEnter(SyMutex *pMutex) -{ -#ifdef _WIN32_WINNT - BOOL rc; - /* Only WindowsNT platforms */ - rc = TryEnterCriticalSection(&pMutex->sMutex); - if( rc ){ - return SXRET_OK; - }else{ - return SXERR_BUSY; - } -#else - return SXERR_NOTIMPLEMENTED; -#endif -} -static void WinMutexLeave(SyMutex *pMutex) -{ - LeaveCriticalSection(&pMutex->sMutex); -} -/* Export Windows mutex interfaces */ -static const SyMutexMethods sWinMutexMethods = { - WinMutexGlobaInit, /* xGlobalInit() */ - WinMutexGlobalRelease, /* xGlobalRelease() */ - WinMutexNew, /* xNew() */ - WinMutexRelease, /* xRelease() */ - WinMutexEnter, /* xEnter() */ - WinMutexTryEnter, /* xTryEnter() */ - WinMutexLeave /* xLeave() */ -}; -JX9_PRIVATE const SyMutexMethods * SyMutexExportMethods(void) -{ - return &sWinMutexMethods; -} -#elif defined(__UNIXES__) -#include -struct SyMutex -{ - pthread_mutex_t sMutex; - sxu32 nType; -}; -static SyMutex * UnixMutexNew(int nType) -{ - static SyMutex aStaticMutexes[] = { - {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_1}, - {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_2}, - {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_3}, - {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_4}, - {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_5}, - {PTHREAD_MUTEX_INITIALIZER, SXMUTEX_TYPE_STATIC_6} - }; - SyMutex *pMutex; - - if( nType == SXMUTEX_TYPE_FAST || nType == SXMUTEX_TYPE_RECURSIVE ){ - pthread_mutexattr_t sRecursiveAttr; - /* Allocate a new mutex */ - pMutex = (SyMutex *)malloc(sizeof(SyMutex)); - if( pMutex == 0 ){ - return 0; - } - if( nType == SXMUTEX_TYPE_RECURSIVE ){ - pthread_mutexattr_init(&sRecursiveAttr); - pthread_mutexattr_settype(&sRecursiveAttr, PTHREAD_MUTEX_RECURSIVE); - } - pthread_mutex_init(&pMutex->sMutex, nType == SXMUTEX_TYPE_RECURSIVE ? &sRecursiveAttr : 0 ); - if( nType == SXMUTEX_TYPE_RECURSIVE ){ - pthread_mutexattr_destroy(&sRecursiveAttr); - } - }else{ - /* Use a pre-allocated static mutex */ - if( nType > SXMUTEX_TYPE_STATIC_6 ){ - nType = SXMUTEX_TYPE_STATIC_6; - } - pMutex = &aStaticMutexes[nType - 3]; - } - pMutex->nType = nType; - - return pMutex; -} -static void UnixMutexRelease(SyMutex *pMutex) -{ - if( pMutex->nType == SXMUTEX_TYPE_FAST || pMutex->nType == SXMUTEX_TYPE_RECURSIVE ){ - pthread_mutex_destroy(&pMutex->sMutex); - free(pMutex); - } -} -static void UnixMutexEnter(SyMutex *pMutex) -{ - pthread_mutex_lock(&pMutex->sMutex); -} -static void UnixMutexLeave(SyMutex *pMutex) -{ - pthread_mutex_unlock(&pMutex->sMutex); -} -/* Export pthread mutex interfaces */ -static const SyMutexMethods sPthreadMutexMethods = { - 0, /* xGlobalInit() */ - 0, /* xGlobalRelease() */ - UnixMutexNew, /* xNew() */ - UnixMutexRelease, /* xRelease() */ - UnixMutexEnter, /* xEnter() */ - 0, /* xTryEnter() */ - UnixMutexLeave /* xLeave() */ -}; -JX9_PRIVATE const SyMutexMethods * SyMutexExportMethods(void) -{ - return &sPthreadMutexMethods; -} -#else -/* Host application must register their own mutex subsystem if the target - * platform is not an UNIX-like or windows systems. - */ -struct SyMutex -{ - sxu32 nType; -}; -static SyMutex * DummyMutexNew(int nType) -{ - static SyMutex sMutex; - SXUNUSED(nType); - return &sMutex; -} -static void DummyMutexRelease(SyMutex *pMutex) -{ - SXUNUSED(pMutex); -} -static void DummyMutexEnter(SyMutex *pMutex) -{ - SXUNUSED(pMutex); -} -static void DummyMutexLeave(SyMutex *pMutex) -{ - SXUNUSED(pMutex); -} -/* Export the dummy mutex interfaces */ -static const SyMutexMethods sDummyMutexMethods = { - 0, /* xGlobalInit() */ - 0, /* xGlobalRelease() */ - DummyMutexNew, /* xNew() */ - DummyMutexRelease, /* xRelease() */ - DummyMutexEnter, /* xEnter() */ - 0, /* xTryEnter() */ - DummyMutexLeave /* xLeave() */ -}; -JX9_PRIVATE const SyMutexMethods * SyMutexExportMethods(void) -{ - return &sDummyMutexMethods; -} -#endif /* __WINNT__ */ -#endif /* JX9_ENABLE_THREADS */ -static void * SyOSHeapAlloc(sxu32 nByte) -{ - void *pNew; -#if defined(__WINNT__) - pNew = HeapAlloc(GetProcessHeap(), 0, nByte); -#else - pNew = malloc((size_t)nByte); -#endif - return pNew; -} -static void * SyOSHeapRealloc(void *pOld, sxu32 nByte) -{ - void *pNew; -#if defined(__WINNT__) - pNew = HeapReAlloc(GetProcessHeap(), 0, pOld, nByte); -#else - pNew = realloc(pOld, (size_t)nByte); -#endif - return pNew; -} -static void SyOSHeapFree(void *pPtr) -{ -#if defined(__WINNT__) - HeapFree(GetProcessHeap(), 0, pPtr); -#else - free(pPtr); -#endif -} -/* SyRunTimeApi:sxstr.c */ -JX9_PRIVATE sxu32 SyStrlen(const char *zSrc) -{ - register const char *zIn = zSrc; -#if defined(UNTRUST) - if( zIn == 0 ){ - return 0; - } -#endif - for(;;){ - if( !zIn[0] ){ break; } zIn++; - if( !zIn[0] ){ break; } zIn++; - if( !zIn[0] ){ break; } zIn++; - if( !zIn[0] ){ break; } zIn++; - } - return (sxu32)(zIn - zSrc); -} -JX9_PRIVATE sxi32 SyByteFind(const char *zStr, sxu32 nLen, sxi32 c, sxu32 *pPos) -{ - const char *zIn = zStr; - const char *zEnd; - - zEnd = &zIn[nLen]; - for(;;){ - if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; - if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; - if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; - if( zIn >= zEnd ){ break; }if( zIn[0] == c ){ if( pPos ){ *pPos = (sxu32)(zIn - zStr); } return SXRET_OK; } zIn++; - } - return SXERR_NOTFOUND; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyByteFind2(const char *zStr, sxu32 nLen, sxi32 c, sxu32 *pPos) -{ - const char *zIn = zStr; - const char *zEnd; - - zEnd = &zIn[nLen - 1]; - for( ;; ){ - if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; - if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; - if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; - if( zEnd < zIn ){ break; } if( zEnd[0] == c ){ if( pPos ){ *pPos = (sxu32)(zEnd - zIn);} return SXRET_OK; } zEnd--; - } - return SXERR_NOTFOUND; -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -JX9_PRIVATE sxi32 SyByteListFind(const char *zSrc, sxu32 nLen, const char *zList, sxu32 *pFirstPos) -{ - const char *zIn = zSrc; - const char *zPtr; - const char *zEnd; - sxi32 c; - zEnd = &zSrc[nLen]; - for(;;){ - if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++; - if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++; - if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++; - if( zIn >= zEnd ){ break; } for(zPtr = zList ; (c = zPtr[0]) != 0 ; zPtr++ ){ if( zIn[0] == c ){ if( pFirstPos ){ *pFirstPos = (sxu32)(zIn - zSrc); } return SXRET_OK; } } zIn++; - } - return SXERR_NOTFOUND; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyStrncmp(const char *zLeft, const char *zRight, sxu32 nLen) -{ - const unsigned char *zP = (const unsigned char *)zLeft; - const unsigned char *zQ = (const unsigned char *)zRight; - - if( SX_EMPTY_STR(zP) || SX_EMPTY_STR(zQ) ){ - return SX_EMPTY_STR(zP) ? (SX_EMPTY_STR(zQ) ? 0 : -1) :1; - } - if( nLen <= 0 ){ - return 0; - } - for(;;){ - if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; - if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; - if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; - if( nLen <= 0 ){ return 0; } if( zP[0] == 0 || zQ[0] == 0 || zP[0] != zQ[0] ){ break; } zP++; zQ++; nLen--; - } - return (sxi32)(zP[0] - zQ[0]); -} -#endif -JX9_PRIVATE sxi32 SyStrnicmp(const char *zLeft, const char *zRight, sxu32 SLen) -{ - register unsigned char *p = (unsigned char *)zLeft; - register unsigned char *q = (unsigned char *)zRight; - - if( SX_EMPTY_STR(p) || SX_EMPTY_STR(q) ){ - return SX_EMPTY_STR(p)? SX_EMPTY_STR(q) ? 0 : -1 :1; - } - for(;;){ - if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; - if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; - if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; - if( !SLen ){ return 0; }if( !*p || !*q || SyCharToLower(*p) != SyCharToLower(*q) ){ break; }p++;q++;--SLen; - - } - return (sxi32)(SyCharToLower(p[0]) - SyCharToLower(q[0])); -} -JX9_PRIVATE sxu32 Systrcpy(char *zDest, sxu32 nDestLen, const char *zSrc, sxu32 nLen) -{ - unsigned char *zBuf = (unsigned char *)zDest; - unsigned char *zIn = (unsigned char *)zSrc; - unsigned char *zEnd; -#if defined(UNTRUST) - if( zSrc == (const char *)zDest ){ - return 0; - } -#endif - if( nLen <= 0 ){ - nLen = SyStrlen(zSrc); - } - zEnd = &zBuf[nDestLen - 1]; /* reserve a room for the null terminator */ - for(;;){ - if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; - if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; - if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; - if( zBuf >= zEnd || nLen == 0 ){ break;} zBuf[0] = zIn[0]; zIn++; zBuf++; nLen--; - } - zBuf[0] = 0; - return (sxu32)(zBuf-(unsigned char *)zDest); -} -/* SyRunTimeApi:sxmem.c */ -JX9_PRIVATE void SyZero(void *pSrc, sxu32 nSize) -{ - register unsigned char *zSrc = (unsigned char *)pSrc; - unsigned char *zEnd; -#if defined(UNTRUST) - if( zSrc == 0 || nSize <= 0 ){ - return ; - } -#endif - zEnd = &zSrc[nSize]; - for(;;){ - if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; - if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; - if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; - if( zSrc >= zEnd ){break;} zSrc[0] = 0; zSrc++; - } -} -JX9_PRIVATE sxi32 SyMemcmp(const void *pB1, const void *pB2, sxu32 nSize) -{ - sxi32 rc; - if( nSize <= 0 ){ - return 0; - } - if( pB1 == 0 || pB2 == 0 ){ - return pB1 != 0 ? 1 : (pB2 == 0 ? 0 : -1); - } - SX_MACRO_FAST_CMP(pB1, pB2, nSize, rc); - return rc; -} -JX9_PRIVATE sxu32 SyMemcpy(const void *pSrc, void *pDest, sxu32 nLen) -{ - if( pSrc == 0 || pDest == 0 ){ - return 0; - } - if( pSrc == (const void *)pDest ){ - return nLen; - } - SX_MACRO_FAST_MEMCPY(pSrc, pDest, nLen); - return nLen; -} -static void * MemOSAlloc(sxu32 nBytes) -{ - sxu32 *pChunk; - pChunk = (sxu32 *)SyOSHeapAlloc(nBytes + sizeof(sxu32)); - if( pChunk == 0 ){ - return 0; - } - pChunk[0] = nBytes; - return (void *)&pChunk[1]; -} -static void * MemOSRealloc(void *pOld, sxu32 nBytes) -{ - sxu32 *pOldChunk; - sxu32 *pChunk; - pOldChunk = (sxu32 *)(((char *)pOld)-sizeof(sxu32)); - if( pOldChunk[0] >= nBytes ){ - return pOld; - } - pChunk = (sxu32 *)SyOSHeapRealloc(pOldChunk, nBytes + sizeof(sxu32)); - if( pChunk == 0 ){ - return 0; - } - pChunk[0] = nBytes; - return (void *)&pChunk[1]; -} -static void MemOSFree(void *pBlock) -{ - void *pChunk; - pChunk = (void *)(((char *)pBlock)-sizeof(sxu32)); - SyOSHeapFree(pChunk); -} -static sxu32 MemOSChunkSize(void *pBlock) -{ - sxu32 *pChunk; - pChunk = (sxu32 *)(((char *)pBlock)-sizeof(sxu32)); - return pChunk[0]; -} -/* Export OS allocation methods */ -static const SyMemMethods sOSAllocMethods = { - MemOSAlloc, - MemOSRealloc, - MemOSFree, - MemOSChunkSize, - 0, - 0, - 0 -}; -static void * MemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte) -{ - SyMemBlock *pBlock; - sxi32 nRetry = 0; - - /* Append an extra block so we can tracks allocated chunks and avoid memory - * leaks. - */ - nByte += sizeof(SyMemBlock); - for(;;){ - pBlock = (SyMemBlock *)pBackend->pMethods->xAlloc(nByte); - if( pBlock != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY - || SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){ - break; - } - nRetry++; - } - if( pBlock == 0 ){ - return 0; - } - pBlock->pNext = pBlock->pPrev = 0; - /* Link to the list of already tracked blocks */ - MACRO_LD_PUSH(pBackend->pBlocks, pBlock); -#if defined(UNTRUST) - pBlock->nGuard = SXMEM_BACKEND_MAGIC; -#endif - pBackend->nBlock++; - return (void *)&pBlock[1]; -} -JX9_PRIVATE void * SyMemBackendAlloc(SyMemBackend *pBackend, sxu32 nByte) -{ - void *pChunk; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) ){ - return 0; - } -#endif - if( pBackend->pMutexMethods ){ - SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex); - } - pChunk = MemBackendAlloc(&(*pBackend), nByte); - if( pBackend->pMutexMethods ){ - SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex); - } - return pChunk; -} -static void * MemBackendRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte) -{ - SyMemBlock *pBlock, *pNew, *pPrev, *pNext; - sxu32 nRetry = 0; - - if( pOld == 0 ){ - return MemBackendAlloc(&(*pBackend), nByte); - } - pBlock = (SyMemBlock *)(((char *)pOld) - sizeof(SyMemBlock)); -#if defined(UNTRUST) - if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){ - return 0; - } -#endif - nByte += sizeof(SyMemBlock); - pPrev = pBlock->pPrev; - pNext = pBlock->pNext; - for(;;){ - pNew = (SyMemBlock *)pBackend->pMethods->xRealloc(pBlock, nByte); - if( pNew != 0 || pBackend->xMemError == 0 || nRetry > SXMEM_BACKEND_RETRY || - SXERR_RETRY != pBackend->xMemError(pBackend->pUserData) ){ - break; - } - nRetry++; - } - if( pNew == 0 ){ - return 0; - } - if( pNew != pBlock ){ - if( pPrev == 0 ){ - pBackend->pBlocks = pNew; - }else{ - pPrev->pNext = pNew; - } - if( pNext ){ - pNext->pPrev = pNew; - } -#if defined(UNTRUST) - pNew->nGuard = SXMEM_BACKEND_MAGIC; -#endif - } - return (void *)&pNew[1]; -} -JX9_PRIVATE void * SyMemBackendRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte) -{ - void *pChunk; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) ){ - return 0; - } -#endif - if( pBackend->pMutexMethods ){ - SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex); - } - pChunk = MemBackendRealloc(&(*pBackend), pOld, nByte); - if( pBackend->pMutexMethods ){ - SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex); - } - return pChunk; -} -static sxi32 MemBackendFree(SyMemBackend *pBackend, void * pChunk) -{ - SyMemBlock *pBlock; - pBlock = (SyMemBlock *)(((char *)pChunk) - sizeof(SyMemBlock)); -#if defined(UNTRUST) - if( pBlock->nGuard != SXMEM_BACKEND_MAGIC ){ - return SXERR_CORRUPT; - } -#endif - /* Unlink from the list of active blocks */ - if( pBackend->nBlock > 0 ){ - /* Release the block */ -#if defined(UNTRUST) - /* Mark as stale block */ - pBlock->nGuard = 0x635B; -#endif - MACRO_LD_REMOVE(pBackend->pBlocks, pBlock); - pBackend->nBlock--; - pBackend->pMethods->xFree(pBlock); - } - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyMemBackendFree(SyMemBackend *pBackend, void * pChunk) -{ - sxi32 rc; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) ){ - return SXERR_CORRUPT; - } -#endif - if( pChunk == 0 ){ - return SXRET_OK; - } - if( pBackend->pMutexMethods ){ - SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex); - } - rc = MemBackendFree(&(*pBackend), pChunk); - if( pBackend->pMutexMethods ){ - SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex); - } - return rc; -} -#if defined(JX9_ENABLE_THREADS) -JX9_PRIVATE sxi32 SyMemBackendMakeThreadSafe(SyMemBackend *pBackend, const SyMutexMethods *pMethods) -{ - SyMutex *pMutex; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) || pMethods == 0 || pMethods->xNew == 0){ - return SXERR_CORRUPT; - } -#endif - pMutex = pMethods->xNew(SXMUTEX_TYPE_FAST); - if( pMutex == 0 ){ - return SXERR_OS; - } - /* Attach the mutex to the memory backend */ - pBackend->pMutex = pMutex; - pBackend->pMutexMethods = pMethods; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyMemBackendDisbaleMutexing(SyMemBackend *pBackend) -{ -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) ){ - return SXERR_CORRUPT; - } -#endif - if( pBackend->pMutex == 0 ){ - /* There is no mutex subsystem at all */ - return SXRET_OK; - } - SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex); - pBackend->pMutexMethods = 0; - pBackend->pMutex = 0; - return SXRET_OK; -} -#endif -/* - * Memory pool allocator - */ -#define SXMEM_POOL_MAGIC 0xDEAD -#define SXMEM_POOL_MAXALLOC (1<<(SXMEM_POOL_NBUCKETS+SXMEM_POOL_INCR)) -#define SXMEM_POOL_MINALLOC (1<<(SXMEM_POOL_INCR)) -static sxi32 MemPoolBucketAlloc(SyMemBackend *pBackend, sxu32 nBucket) -{ - char *zBucket, *zBucketEnd; - SyMemHeader *pHeader; - sxu32 nBucketSize; - - /* Allocate one big block first */ - zBucket = (char *)MemBackendAlloc(&(*pBackend), SXMEM_POOL_MAXALLOC); - if( zBucket == 0 ){ - return SXERR_MEM; - } - zBucketEnd = &zBucket[SXMEM_POOL_MAXALLOC]; - /* Divide the big block into mini bucket pool */ - nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR); - pBackend->apPool[nBucket] = pHeader = (SyMemHeader *)zBucket; - for(;;){ - if( &zBucket[nBucketSize] >= zBucketEnd ){ - break; - } - pHeader->pNext = (SyMemHeader *)&zBucket[nBucketSize]; - /* Advance the cursor to the next available chunk */ - pHeader = pHeader->pNext; - zBucket += nBucketSize; - } - pHeader->pNext = 0; - - return SXRET_OK; -} -static void * MemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte) -{ - SyMemHeader *pBucket, *pNext; - sxu32 nBucketSize; - sxu32 nBucket; - - if( nByte + sizeof(SyMemHeader) >= SXMEM_POOL_MAXALLOC ){ - /* Allocate a big chunk directly */ - pBucket = (SyMemHeader *)MemBackendAlloc(&(*pBackend), nByte+sizeof(SyMemHeader)); - if( pBucket == 0 ){ - return 0; - } - /* Record as big block */ - pBucket->nBucket = (sxu32)(SXMEM_POOL_MAGIC << 16) | SXU16_HIGH; - return (void *)(pBucket+1); - } - /* Locate the appropriate bucket */ - nBucket = 0; - nBucketSize = SXMEM_POOL_MINALLOC; - while( nByte + sizeof(SyMemHeader) > nBucketSize ){ - nBucketSize <<= 1; - nBucket++; - } - pBucket = pBackend->apPool[nBucket]; - if( pBucket == 0 ){ - sxi32 rc; - rc = MemPoolBucketAlloc(&(*pBackend), nBucket); - if( rc != SXRET_OK ){ - return 0; - } - pBucket = pBackend->apPool[nBucket]; - } - /* Remove from the free list */ - pNext = pBucket->pNext; - pBackend->apPool[nBucket] = pNext; - /* Record bucket&magic number */ - pBucket->nBucket = (SXMEM_POOL_MAGIC << 16) | nBucket; - return (void *)&pBucket[1]; -} -JX9_PRIVATE void * SyMemBackendPoolAlloc(SyMemBackend *pBackend, sxu32 nByte) -{ - void *pChunk; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) ){ - return 0; - } -#endif - if( pBackend->pMutexMethods ){ - SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex); - } - pChunk = MemBackendPoolAlloc(&(*pBackend), nByte); - if( pBackend->pMutexMethods ){ - SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex); - } - return pChunk; -} -static sxi32 MemBackendPoolFree(SyMemBackend *pBackend, void * pChunk) -{ - SyMemHeader *pHeader; - sxu32 nBucket; - /* Get the corresponding bucket */ - pHeader = (SyMemHeader *)(((char *)pChunk) - sizeof(SyMemHeader)); - /* Sanity check to avoid misuse */ - if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){ - return SXERR_CORRUPT; - } - nBucket = pHeader->nBucket & 0xFFFF; - if( nBucket == SXU16_HIGH ){ - /* Free the big block */ - MemBackendFree(&(*pBackend), pHeader); - }else{ - /* Return to the free list */ - pHeader->pNext = pBackend->apPool[nBucket & 0x0f]; - pBackend->apPool[nBucket & 0x0f] = pHeader; - } - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyMemBackendPoolFree(SyMemBackend *pBackend, void * pChunk) -{ - sxi32 rc; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) || pChunk == 0 ){ - return SXERR_CORRUPT; - } -#endif - if( pBackend->pMutexMethods ){ - SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex); - } - rc = MemBackendPoolFree(&(*pBackend), pChunk); - if( pBackend->pMutexMethods ){ - SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex); - } - return rc; -} -#if 0 -static void * MemBackendPoolRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte) -{ - sxu32 nBucket, nBucketSize; - SyMemHeader *pHeader; - void * pNew; - - if( pOld == 0 ){ - /* Allocate a new pool */ - pNew = MemBackendPoolAlloc(&(*pBackend), nByte); - return pNew; - } - /* Get the corresponding bucket */ - pHeader = (SyMemHeader *)(((char *)pOld) - sizeof(SyMemHeader)); - /* Sanity check to avoid misuse */ - if( (pHeader->nBucket >> 16) != SXMEM_POOL_MAGIC ){ - return 0; - } - nBucket = pHeader->nBucket & 0xFFFF; - if( nBucket == SXU16_HIGH ){ - /* Big block */ - return MemBackendRealloc(&(*pBackend), pHeader, nByte); - } - nBucketSize = 1 << (nBucket + SXMEM_POOL_INCR); - if( nBucketSize >= nByte + sizeof(SyMemHeader) ){ - /* The old bucket can honor the requested size */ - return pOld; - } - /* Allocate a new pool */ - pNew = MemBackendPoolAlloc(&(*pBackend), nByte); - if( pNew == 0 ){ - return 0; - } - /* Copy the old data into the new block */ - SyMemcpy(pOld, pNew, nBucketSize); - /* Free the stale block */ - MemBackendPoolFree(&(*pBackend), pOld); - return pNew; -} -JX9_PRIVATE void * SyMemBackendPoolRealloc(SyMemBackend *pBackend, void * pOld, sxu32 nByte) -{ - void *pChunk; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) ){ - return 0; - } -#endif - if( pBackend->pMutexMethods ){ - SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex); - } - pChunk = MemBackendPoolRealloc(&(*pBackend), pOld, nByte); - if( pBackend->pMutexMethods ){ - SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex); - } - return pChunk; -} -#endif -JX9_PRIVATE sxi32 SyMemBackendInit(SyMemBackend *pBackend, ProcMemError xMemErr, void * pUserData) -{ -#if defined(UNTRUST) - if( pBackend == 0 ){ - return SXERR_EMPTY; - } -#endif - /* Zero the allocator first */ - SyZero(&(*pBackend), sizeof(SyMemBackend)); - pBackend->xMemError = xMemErr; - pBackend->pUserData = pUserData; - /* Switch to the OS memory allocator */ - pBackend->pMethods = &sOSAllocMethods; - if( pBackend->pMethods->xInit ){ - /* Initialize the backend */ - if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){ - return SXERR_ABORT; - } - } -#if defined(UNTRUST) - pBackend->nMagic = SXMEM_BACKEND_MAGIC; -#endif - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyMemBackendInitFromOthers(SyMemBackend *pBackend, const SyMemMethods *pMethods, ProcMemError xMemErr, void * pUserData) -{ -#if defined(UNTRUST) - if( pBackend == 0 || pMethods == 0){ - return SXERR_EMPTY; - } -#endif - if( pMethods->xAlloc == 0 || pMethods->xRealloc == 0 || pMethods->xFree == 0 || pMethods->xChunkSize == 0 ){ - /* mandatory methods are missing */ - return SXERR_INVALID; - } - /* Zero the allocator first */ - SyZero(&(*pBackend), sizeof(SyMemBackend)); - pBackend->xMemError = xMemErr; - pBackend->pUserData = pUserData; - /* Switch to the host application memory allocator */ - pBackend->pMethods = pMethods; - if( pBackend->pMethods->xInit ){ - /* Initialize the backend */ - if( SXRET_OK != pBackend->pMethods->xInit(pBackend->pMethods->pUserData) ){ - return SXERR_ABORT; - } - } -#if defined(UNTRUST) - pBackend->nMagic = SXMEM_BACKEND_MAGIC; -#endif - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyMemBackendInitFromParent(SyMemBackend *pBackend,const SyMemBackend *pParent) -{ - sxu8 bInheritMutex; -#if defined(UNTRUST) - if( pBackend == 0 || SXMEM_BACKEND_CORRUPT(pParent) ){ - return SXERR_CORRUPT; - } -#endif - /* Zero the allocator first */ - SyZero(&(*pBackend), sizeof(SyMemBackend)); - pBackend->pMethods = pParent->pMethods; - pBackend->xMemError = pParent->xMemError; - pBackend->pUserData = pParent->pUserData; - bInheritMutex = pParent->pMutexMethods ? TRUE : FALSE; - if( bInheritMutex ){ - pBackend->pMutexMethods = pParent->pMutexMethods; - /* Create a private mutex */ - pBackend->pMutex = pBackend->pMutexMethods->xNew(SXMUTEX_TYPE_FAST); - if( pBackend->pMutex == 0){ - return SXERR_OS; - } - } -#if defined(UNTRUST) - pBackend->nMagic = SXMEM_BACKEND_MAGIC; -#endif - return SXRET_OK; -} -static sxi32 MemBackendRelease(SyMemBackend *pBackend) -{ - SyMemBlock *pBlock, *pNext; - - pBlock = pBackend->pBlocks; - for(;;){ - if( pBackend->nBlock == 0 ){ - break; - } - pNext = pBlock->pNext; - pBackend->pMethods->xFree(pBlock); - pBlock = pNext; - pBackend->nBlock--; - /* LOOP ONE */ - if( pBackend->nBlock == 0 ){ - break; - } - pNext = pBlock->pNext; - pBackend->pMethods->xFree(pBlock); - pBlock = pNext; - pBackend->nBlock--; - /* LOOP TWO */ - if( pBackend->nBlock == 0 ){ - break; - } - pNext = pBlock->pNext; - pBackend->pMethods->xFree(pBlock); - pBlock = pNext; - pBackend->nBlock--; - /* LOOP THREE */ - if( pBackend->nBlock == 0 ){ - break; - } - pNext = pBlock->pNext; - pBackend->pMethods->xFree(pBlock); - pBlock = pNext; - pBackend->nBlock--; - /* LOOP FOUR */ - } - if( pBackend->pMethods->xRelease ){ - pBackend->pMethods->xRelease(pBackend->pMethods->pUserData); - } - pBackend->pMethods = 0; - pBackend->pBlocks = 0; -#if defined(UNTRUST) - pBackend->nMagic = 0x2626; -#endif - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyMemBackendRelease(SyMemBackend *pBackend) -{ - sxi32 rc; -#if defined(UNTRUST) - if( SXMEM_BACKEND_CORRUPT(pBackend) ){ - return SXERR_INVALID; - } -#endif - if( pBackend->pMutexMethods ){ - SyMutexEnter(pBackend->pMutexMethods, pBackend->pMutex); - } - rc = MemBackendRelease(&(*pBackend)); - if( pBackend->pMutexMethods ){ - SyMutexLeave(pBackend->pMutexMethods, pBackend->pMutex); - SyMutexRelease(pBackend->pMutexMethods, pBackend->pMutex); - } - return rc; -} -JX9_PRIVATE void * SyMemBackendDup(SyMemBackend *pBackend, const void *pSrc, sxu32 nSize) -{ - void *pNew; -#if defined(UNTRUST) - if( pSrc == 0 || nSize <= 0 ){ - return 0; - } -#endif - pNew = SyMemBackendAlloc(&(*pBackend), nSize); - if( pNew ){ - SyMemcpy(pSrc, pNew, nSize); - } - return pNew; -} -JX9_PRIVATE char * SyMemBackendStrDup(SyMemBackend *pBackend, const char *zSrc, sxu32 nSize) -{ - char *zDest; - zDest = (char *)SyMemBackendAlloc(&(*pBackend), nSize + 1); - if( zDest ){ - Systrcpy(zDest, nSize+1, zSrc, nSize); - } - return zDest; -} -JX9_PRIVATE sxi32 SyBlobInitFromBuf(SyBlob *pBlob, void *pBuffer, sxu32 nSize) -{ -#if defined(UNTRUST) - if( pBlob == 0 || pBuffer == 0 || nSize < 1 ){ - return SXERR_EMPTY; - } -#endif - pBlob->pBlob = pBuffer; - pBlob->mByte = nSize; - pBlob->nByte = 0; - pBlob->pAllocator = 0; - pBlob->nFlags = SXBLOB_LOCKED|SXBLOB_STATIC; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyBlobInit(SyBlob *pBlob, SyMemBackend *pAllocator) -{ -#if defined(UNTRUST) - if( pBlob == 0 ){ - return SXERR_EMPTY; - } -#endif - pBlob->pBlob = 0; - pBlob->mByte = pBlob->nByte = 0; - pBlob->pAllocator = &(*pAllocator); - pBlob->nFlags = 0; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyBlobReadOnly(SyBlob *pBlob, const void *pData, sxu32 nByte) -{ -#if defined(UNTRUST) - if( pBlob == 0 ){ - return SXERR_EMPTY; - } -#endif - pBlob->pBlob = (void *)pData; - pBlob->nByte = nByte; - pBlob->mByte = 0; - pBlob->nFlags |= SXBLOB_RDONLY; - return SXRET_OK; -} -#ifndef SXBLOB_MIN_GROWTH -#define SXBLOB_MIN_GROWTH 16 -#endif -static sxi32 BlobPrepareGrow(SyBlob *pBlob, sxu32 *pByte) -{ - sxu32 nByte; - void *pNew; - nByte = *pByte; - if( pBlob->nFlags & (SXBLOB_LOCKED|SXBLOB_STATIC) ){ - if ( SyBlobFreeSpace(pBlob) < nByte ){ - *pByte = SyBlobFreeSpace(pBlob); - if( (*pByte) == 0 ){ - return SXERR_SHORT; - } - } - return SXRET_OK; - } - if( pBlob->nFlags & SXBLOB_RDONLY ){ - /* Make a copy of the read-only item */ - if( pBlob->nByte > 0 ){ - pNew = SyMemBackendDup(pBlob->pAllocator, pBlob->pBlob, pBlob->nByte); - if( pNew == 0 ){ - return SXERR_MEM; - } - pBlob->pBlob = pNew; - pBlob->mByte = pBlob->nByte; - }else{ - pBlob->pBlob = 0; - pBlob->mByte = 0; - } - /* Remove the read-only flag */ - pBlob->nFlags &= ~SXBLOB_RDONLY; - } - if( SyBlobFreeSpace(pBlob) >= nByte ){ - return SXRET_OK; - } - if( pBlob->mByte > 0 ){ - nByte = nByte + pBlob->mByte * 2 + SXBLOB_MIN_GROWTH; - }else if ( nByte < SXBLOB_MIN_GROWTH ){ - nByte = SXBLOB_MIN_GROWTH; - } - pNew = SyMemBackendRealloc(pBlob->pAllocator, pBlob->pBlob, nByte); - if( pNew == 0 ){ - return SXERR_MEM; - } - pBlob->pBlob = pNew; - pBlob->mByte = nByte; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyBlobAppend(SyBlob *pBlob, const void *pData, sxu32 nSize) -{ - sxu8 *zBlob; - sxi32 rc; - if( nSize < 1 ){ - return SXRET_OK; - } - rc = BlobPrepareGrow(&(*pBlob), &nSize); - if( SXRET_OK != rc ){ - return rc; - } - if( pData ){ - zBlob = (sxu8 *)pBlob->pBlob ; - zBlob = &zBlob[pBlob->nByte]; - pBlob->nByte += nSize; - SX_MACRO_FAST_MEMCPY(pData, zBlob, nSize); - } - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyBlobNullAppend(SyBlob *pBlob) -{ - sxi32 rc; - sxu32 n; - n = pBlob->nByte; - rc = SyBlobAppend(&(*pBlob), (const void *)"\0", sizeof(char)); - if (rc == SXRET_OK ){ - pBlob->nByte = n; - } - return rc; -} -JX9_PRIVATE sxi32 SyBlobDup(SyBlob *pSrc, SyBlob *pDest) -{ - sxi32 rc = SXRET_OK; - if( pSrc->nByte > 0 ){ - rc = SyBlobAppend(&(*pDest), pSrc->pBlob, pSrc->nByte); - } - return rc; -} -JX9_PRIVATE sxi32 SyBlobReset(SyBlob *pBlob) -{ - pBlob->nByte = 0; - if( pBlob->nFlags & SXBLOB_RDONLY ){ - /* Read-only (Not malloced chunk) */ - pBlob->pBlob = 0; - pBlob->mByte = 0; - pBlob->nFlags &= ~SXBLOB_RDONLY; - } - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyBlobTruncate(SyBlob *pBlob,sxu32 nNewLen) -{ - if( nNewLen < pBlob->nByte ){ - pBlob->nByte = nNewLen; - } - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyBlobRelease(SyBlob *pBlob) -{ - if( (pBlob->nFlags & (SXBLOB_STATIC|SXBLOB_RDONLY)) == 0 && pBlob->mByte > 0 ){ - SyMemBackendFree(pBlob->pAllocator, pBlob->pBlob); - } - pBlob->pBlob = 0; - pBlob->nByte = pBlob->mByte = 0; - pBlob->nFlags = 0; - return SXRET_OK; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyBlobSearch(const void *pBlob, sxu32 nLen, const void *pPattern, sxu32 pLen, sxu32 *pOfft) -{ - const char *zIn = (const char *)pBlob; - const char *zEnd; - sxi32 rc; - if( pLen > nLen ){ - return SXERR_NOTFOUND; - } - zEnd = &zIn[nLen-pLen]; - for(;;){ - if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++; - if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++; - if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++; - if( zIn > zEnd ){break;} SX_MACRO_FAST_CMP(zIn, pPattern, pLen, rc); if( rc == 0 ){ if( pOfft ){ *pOfft = (sxu32)(zIn - (const char *)pBlob);} return SXRET_OK; } zIn++; - } - return SXERR_NOTFOUND; -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* SyRunTimeApi:sxds.c */ -JX9_PRIVATE sxi32 SySetInit(SySet *pSet, SyMemBackend *pAllocator, sxu32 ElemSize) -{ - pSet->nSize = 0 ; - pSet->nUsed = 0; - pSet->nCursor = 0; - pSet->eSize = ElemSize; - pSet->pAllocator = pAllocator; - pSet->pBase = 0; - pSet->pUserData = 0; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SySetPut(SySet *pSet, const void *pItem) -{ - unsigned char *zbase; - if( pSet->nUsed >= pSet->nSize ){ - void *pNew; - if( pSet->pAllocator == 0 ){ - return SXERR_LOCKED; - } - if( pSet->nSize <= 0 ){ - pSet->nSize = 4; - } - pNew = SyMemBackendRealloc(pSet->pAllocator, pSet->pBase, pSet->eSize * pSet->nSize * 2); - if( pNew == 0 ){ - return SXERR_MEM; - } - pSet->pBase = pNew; - pSet->nSize <<= 1; - } - zbase = (unsigned char *)pSet->pBase; - SX_MACRO_FAST_MEMCPY(pItem, &zbase[pSet->nUsed * pSet->eSize], pSet->eSize); - pSet->nUsed++; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SySetAlloc(SySet *pSet, sxi32 nItem) -{ - if( pSet->nSize > 0 ){ - return SXERR_LOCKED; - } - if( nItem < 8 ){ - nItem = 8; - } - pSet->pBase = SyMemBackendAlloc(pSet->pAllocator, pSet->eSize * nItem); - if( pSet->pBase == 0 ){ - return SXERR_MEM; - } - pSet->nSize = nItem; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SySetReset(SySet *pSet) -{ - pSet->nUsed = 0; - pSet->nCursor = 0; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SySetResetCursor(SySet *pSet) -{ - pSet->nCursor = 0; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SySetGetNextEntry(SySet *pSet, void **ppEntry) -{ - register unsigned char *zSrc; - if( pSet->nCursor >= pSet->nUsed ){ - /* Reset cursor */ - pSet->nCursor = 0; - return SXERR_EOF; - } - zSrc = (unsigned char *)SySetBasePtr(pSet); - if( ppEntry ){ - *ppEntry = (void *)&zSrc[pSet->nCursor * pSet->eSize]; - } - pSet->nCursor++; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SySetRelease(SySet *pSet) -{ - sxi32 rc = SXRET_OK; - if( pSet->pAllocator && pSet->pBase ){ - rc = SyMemBackendFree(pSet->pAllocator, pSet->pBase); - } - pSet->pBase = 0; - pSet->nUsed = 0; - pSet->nCursor = 0; - return rc; -} -JX9_PRIVATE void * SySetPeek(SySet *pSet) -{ - const char *zBase; - if( pSet->nUsed <= 0 ){ - return 0; - } - zBase = (const char *)pSet->pBase; - return (void *)&zBase[(pSet->nUsed - 1) * pSet->eSize]; -} -JX9_PRIVATE void * SySetPop(SySet *pSet) -{ - const char *zBase; - void *pData; - if( pSet->nUsed <= 0 ){ - return 0; - } - zBase = (const char *)pSet->pBase; - pSet->nUsed--; - pData = (void *)&zBase[pSet->nUsed * pSet->eSize]; - return pData; -} -JX9_PRIVATE void * SySetAt(SySet *pSet, sxu32 nIdx) -{ - const char *zBase; - if( nIdx >= pSet->nUsed ){ - /* Out of range */ - return 0; - } - zBase = (const char *)pSet->pBase; - return (void *)&zBase[nIdx * pSet->eSize]; -} -/* Private hash entry */ -struct SyHashEntry_Pr -{ - const void *pKey; /* Hash key */ - sxu32 nKeyLen; /* Key length */ - void *pUserData; /* User private data */ - /* Private fields */ - sxu32 nHash; - SyHash *pHash; - SyHashEntry_Pr *pNext, *pPrev; /* Next and previous entry in the list */ - SyHashEntry_Pr *pNextCollide, *pPrevCollide; /* Collision list */ -}; -#define INVALID_HASH(H) ((H)->apBucket == 0) -JX9_PRIVATE sxi32 SyHashInit(SyHash *pHash, SyMemBackend *pAllocator, ProcHash xHash, ProcCmp xCmp) -{ - SyHashEntry_Pr **apNew; -#if defined(UNTRUST) - if( pHash == 0 ){ - return SXERR_EMPTY; - } -#endif - /* Allocate a new table */ - apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(&(*pAllocator), sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE); - if( apNew == 0 ){ - return SXERR_MEM; - } - SyZero((void *)apNew, sizeof(SyHashEntry_Pr *) * SXHASH_BUCKET_SIZE); - pHash->pAllocator = &(*pAllocator); - pHash->xHash = xHash ? xHash : SyBinHash; - pHash->xCmp = xCmp ? xCmp : SyMemcmp; - pHash->pCurrent = pHash->pList = 0; - pHash->nEntry = 0; - pHash->apBucket = apNew; - pHash->nBucketSize = SXHASH_BUCKET_SIZE; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyHashRelease(SyHash *pHash) -{ - SyHashEntry_Pr *pEntry, *pNext; -#if defined(UNTRUST) - if( INVALID_HASH(pHash) ){ - return SXERR_EMPTY; - } -#endif - pEntry = pHash->pList; - for(;;){ - if( pHash->nEntry == 0 ){ - break; - } - pNext = pEntry->pNext; - SyMemBackendPoolFree(pHash->pAllocator, pEntry); - pEntry = pNext; - pHash->nEntry--; - } - if( pHash->apBucket ){ - SyMemBackendFree(pHash->pAllocator, (void *)pHash->apBucket); - } - pHash->apBucket = 0; - pHash->nBucketSize = 0; - pHash->pAllocator = 0; - return SXRET_OK; -} -static SyHashEntry_Pr * HashGetEntry(SyHash *pHash, const void *pKey, sxu32 nKeyLen) -{ - SyHashEntry_Pr *pEntry; - sxu32 nHash; - - nHash = pHash->xHash(pKey, nKeyLen); - pEntry = pHash->apBucket[nHash & (pHash->nBucketSize - 1)]; - for(;;){ - if( pEntry == 0 ){ - break; - } - if( pEntry->nHash == nHash && pEntry->nKeyLen == nKeyLen && - pHash->xCmp(pEntry->pKey, pKey, nKeyLen) == 0 ){ - return pEntry; - } - pEntry = pEntry->pNextCollide; - } - /* Entry not found */ - return 0; -} -JX9_PRIVATE SyHashEntry * SyHashGet(SyHash *pHash, const void *pKey, sxu32 nKeyLen) -{ - SyHashEntry_Pr *pEntry; -#if defined(UNTRUST) - if( INVALID_HASH(pHash) ){ - return 0; - } -#endif - if( pHash->nEntry < 1 || nKeyLen < 1 ){ - /* Don't bother hashing, return immediately */ - return 0; - } - pEntry = HashGetEntry(&(*pHash), pKey, nKeyLen); - if( pEntry == 0 ){ - return 0; - } - return (SyHashEntry *)pEntry; -} -static sxi32 HashDeleteEntry(SyHash *pHash, SyHashEntry_Pr *pEntry, void **ppUserData) -{ - sxi32 rc; - if( pEntry->pPrevCollide == 0 ){ - pHash->apBucket[pEntry->nHash & (pHash->nBucketSize - 1)] = pEntry->pNextCollide; - }else{ - pEntry->pPrevCollide->pNextCollide = pEntry->pNextCollide; - } - if( pEntry->pNextCollide ){ - pEntry->pNextCollide->pPrevCollide = pEntry->pPrevCollide; - } - MACRO_LD_REMOVE(pHash->pList, pEntry); - pHash->nEntry--; - if( ppUserData ){ - /* Write a pointer to the user data */ - *ppUserData = pEntry->pUserData; - } - /* Release the entry */ - rc = SyMemBackendPoolFree(pHash->pAllocator, pEntry); - return rc; -} -JX9_PRIVATE sxi32 SyHashDeleteEntry(SyHash *pHash, const void *pKey, sxu32 nKeyLen, void **ppUserData) -{ - SyHashEntry_Pr *pEntry; - sxi32 rc; -#if defined(UNTRUST) - if( INVALID_HASH(pHash) ){ - return SXERR_CORRUPT; - } -#endif - pEntry = HashGetEntry(&(*pHash), pKey, nKeyLen); - if( pEntry == 0 ){ - return SXERR_NOTFOUND; - } - rc = HashDeleteEntry(&(*pHash), pEntry, ppUserData); - return rc; -} -JX9_PRIVATE sxi32 SyHashForEach(SyHash *pHash, sxi32 (*xStep)(SyHashEntry *, void *), void *pUserData) -{ - SyHashEntry_Pr *pEntry; - sxi32 rc; - sxu32 n; -#if defined(UNTRUST) - if( INVALID_HASH(pHash) || xStep == 0){ - return 0; - } -#endif - pEntry = pHash->pList; - for( n = 0 ; n < pHash->nEntry ; n++ ){ - /* Invoke the callback */ - rc = xStep((SyHashEntry *)pEntry, pUserData); - if( rc != SXRET_OK ){ - return rc; - } - /* Point to the next entry */ - pEntry = pEntry->pNext; - } - return SXRET_OK; -} -static sxi32 HashGrowTable(SyHash *pHash) -{ - sxu32 nNewSize = pHash->nBucketSize * 2; - SyHashEntry_Pr *pEntry; - SyHashEntry_Pr **apNew; - sxu32 n, iBucket; - - /* Allocate a new larger table */ - apNew = (SyHashEntry_Pr **)SyMemBackendAlloc(pHash->pAllocator, nNewSize * sizeof(SyHashEntry_Pr *)); - if( apNew == 0 ){ - /* Not so fatal, simply a performance hit */ - return SXRET_OK; - } - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(SyHashEntry_Pr *)); - /* Rehash all entries */ - for( n = 0, pEntry = pHash->pList; n < pHash->nEntry ; n++ ){ - pEntry->pNextCollide = pEntry->pPrevCollide = 0; - /* Install in the new bucket */ - iBucket = pEntry->nHash & (nNewSize - 1); - pEntry->pNextCollide = apNew[iBucket]; - if( apNew[iBucket] != 0 ){ - apNew[iBucket]->pPrevCollide = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(pHash->pAllocator, (void *)pHash->apBucket); - pHash->apBucket = apNew; - pHash->nBucketSize = nNewSize; - return SXRET_OK; -} -static sxi32 HashInsert(SyHash *pHash, SyHashEntry_Pr *pEntry) -{ - sxu32 iBucket = pEntry->nHash & (pHash->nBucketSize - 1); - /* Insert the entry in its corresponding bcuket */ - pEntry->pNextCollide = pHash->apBucket[iBucket]; - if( pHash->apBucket[iBucket] != 0 ){ - pHash->apBucket[iBucket]->pPrevCollide = pEntry; - } - pHash->apBucket[iBucket] = pEntry; - /* Link to the entry list */ - MACRO_LD_PUSH(pHash->pList, pEntry); - if( pHash->nEntry == 0 ){ - pHash->pCurrent = pHash->pList; - } - pHash->nEntry++; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyHashInsert(SyHash *pHash, const void *pKey, sxu32 nKeyLen, void *pUserData) -{ - SyHashEntry_Pr *pEntry; - sxi32 rc; -#if defined(UNTRUST) - if( INVALID_HASH(pHash) || pKey == 0 ){ - return SXERR_CORRUPT; - } -#endif - if( pHash->nEntry >= pHash->nBucketSize * SXHASH_FILL_FACTOR ){ - rc = HashGrowTable(&(*pHash)); - if( rc != SXRET_OK ){ - return rc; - } - } - /* Allocate a new hash entry */ - pEntry = (SyHashEntry_Pr *)SyMemBackendPoolAlloc(pHash->pAllocator, sizeof(SyHashEntry_Pr)); - if( pEntry == 0 ){ - return SXERR_MEM; - } - /* Zero the entry */ - SyZero(pEntry, sizeof(SyHashEntry_Pr)); - pEntry->pHash = pHash; - pEntry->pKey = pKey; - pEntry->nKeyLen = nKeyLen; - pEntry->pUserData = pUserData; - pEntry->nHash = pHash->xHash(pEntry->pKey, pEntry->nKeyLen); - /* Finally insert the entry in its corresponding bucket */ - rc = HashInsert(&(*pHash), pEntry); - return rc; -} -/* SyRunTimeApi:sxutils.c */ -JX9_PRIVATE sxi32 SyStrIsNumeric(const char *zSrc, sxu32 nLen, sxu8 *pReal, const char **pzTail) -{ - const char *zCur, *zEnd; -#ifdef UNTRUST - if( SX_EMPTY_STR(zSrc) ){ - return SXERR_EMPTY; - } -#endif - zEnd = &zSrc[nLen]; - /* Jump leading white spaces */ - while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){ - zSrc++; - } - zCur = zSrc; - if( pReal ){ - *pReal = FALSE; - } - for(;;){ - if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; - if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; - if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; - if( zSrc >= zEnd || (unsigned char)zSrc[0] >= 0xc0 || !SyisDigit(zSrc[0]) ){ break; } zSrc++; - }; - if( zSrc < zEnd && zSrc > zCur ){ - int c = zSrc[0]; - if( c == '.' ){ - zSrc++; - if( pReal ){ - *pReal = TRUE; - } - if( pzTail ){ - while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && (zSrc[0] == 'e' || zSrc[0] == 'E') ){ - zSrc++; - if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){ - zSrc++; - } - while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){ - zSrc++; - } - } - } - }else if( c == 'e' || c == 'E' ){ - zSrc++; - if( pReal ){ - *pReal = TRUE; - } - if( pzTail ){ - if( zSrc < zEnd && (zSrc[0] == '+' || zSrc[0] == '-') ){ - zSrc++; - } - while( zSrc < zEnd && (unsigned char)zSrc[0] < 0xc0 && SyisDigit(zSrc[0]) ){ - zSrc++; - } - } - } - } - if( pzTail ){ - /* Point to the non numeric part */ - *pzTail = zSrc; - } - return zSrc > zCur ? SXRET_OK /* String prefix is numeric */ : SXERR_INVALID /* Not a digit stream */; -} -#define SXINT32_MIN_STR "2147483648" -#define SXINT32_MAX_STR "2147483647" -#define SXINT64_MIN_STR "9223372036854775808" -#define SXINT64_MAX_STR "9223372036854775807" -JX9_PRIVATE sxi32 SyStrToInt32(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest) -{ - int isNeg = FALSE; - const char *zEnd; - sxi32 nVal = 0; - sxi16 i; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zSrc) ){ - if( pOutVal ){ - *(sxi32 *)pOutVal = 0; - } - return SXERR_EMPTY; - } -#endif - zEnd = &zSrc[nLen]; - while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ - isNeg = (zSrc[0] == '-') ? TRUE :FALSE; - zSrc++; - } - /* Skip leading zero */ - while(zSrc < zEnd && zSrc[0] == '0' ){ - zSrc++; - } - i = 10; - if( (sxu32)(zEnd-zSrc) >= 10 ){ - /* Handle overflow */ - i = SyMemcmp(zSrc, (isNeg == TRUE) ? SXINT32_MIN_STR : SXINT32_MAX_STR, nLen) <= 0 ? 10 : 9; - } - for(;;){ - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - } - /* Skip trailing spaces */ - while(zSrc < zEnd && SyisSpace(zSrc[0])){ - zSrc++; - } - if( zRest ){ - *zRest = (char *)zSrc; - } - if( pOutVal ){ - if( isNeg == TRUE && nVal != 0 ){ - nVal = -nVal; - } - *(sxi32 *)pOutVal = nVal; - } - return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; -} -JX9_PRIVATE sxi32 SyStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest) -{ - int isNeg = FALSE; - const char *zEnd; - sxi64 nVal; - sxi16 i; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zSrc) ){ - if( pOutVal ){ - *(sxi32 *)pOutVal = 0; - } - return SXERR_EMPTY; - } -#endif - zEnd = &zSrc[nLen]; - while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ - isNeg = (zSrc[0] == '-') ? TRUE :FALSE; - zSrc++; - } - /* Skip leading zero */ - while(zSrc < zEnd && zSrc[0] == '0' ){ - zSrc++; - } - i = 19; - if( (sxu32)(zEnd-zSrc) >= 19 ){ - i = SyMemcmp(zSrc, isNeg ? SXINT64_MIN_STR : SXINT64_MAX_STR, 19) <= 0 ? 19 : 18 ; - } - nVal = 0; - for(;;){ - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - if(zSrc >= zEnd || !i || !SyisDigit(zSrc[0])){ break; } nVal = nVal * 10 + ( zSrc[0] - '0' ) ; --i ; zSrc++; - } - /* Skip trailing spaces */ - while(zSrc < zEnd && SyisSpace(zSrc[0])){ - zSrc++; - } - if( zRest ){ - *zRest = (char *)zSrc; - } - if( pOutVal ){ - if( isNeg == TRUE && nVal != 0 ){ - nVal = -nVal; - } - *(sxi64 *)pOutVal = nVal; - } - return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; -} -JX9_PRIVATE sxi32 SyHexToint(sxi32 c) -{ - switch(c){ - case '0': return 0; - case '1': return 1; - case '2': return 2; - case '3': return 3; - case '4': return 4; - case '5': return 5; - case '6': return 6; - case '7': return 7; - case '8': return 8; - case '9': return 9; - case 'A': case 'a': return 10; - case 'B': case 'b': return 11; - case 'C': case 'c': return 12; - case 'D': case 'd': return 13; - case 'E': case 'e': return 14; - case 'F': case 'f': return 15; - } - return -1; -} -JX9_PRIVATE sxi32 SyHexStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest) -{ - const char *zIn, *zEnd; - int isNeg = FALSE; - sxi64 nVal = 0; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zSrc) ){ - if( pOutVal ){ - *(sxi32 *)pOutVal = 0; - } - return SXERR_EMPTY; - } -#endif - zEnd = &zSrc[nLen]; - while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && ( *zSrc == '-' || *zSrc == '+' ) ){ - isNeg = (zSrc[0] == '-') ? TRUE :FALSE; - zSrc++; - } - if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'x' || zSrc[1] == 'X') ){ - /* Bypass hex prefix */ - zSrc += sizeof(char) * 2; - } - /* Skip leading zero */ - while(zSrc < zEnd && zSrc[0] == '0' ){ - zSrc++; - } - zIn = zSrc; - for(;;){ - if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; - if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; - if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; - if(zSrc >= zEnd || !SyisHex(zSrc[0]) || (int)(zSrc-zIn) > 15) break; nVal = nVal * 16 + SyHexToint(zSrc[0]); zSrc++ ; - } - while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zRest ){ - *zRest = zSrc; - } - if( pOutVal ){ - if( isNeg == TRUE && nVal != 0 ){ - nVal = -nVal; - } - *(sxi64 *)pOutVal = nVal; - } - return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX; -} -JX9_PRIVATE sxi32 SyOctalStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest) -{ - const char *zIn, *zEnd; - int isNeg = FALSE; - sxi64 nVal = 0; - int c; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zSrc) ){ - if( pOutVal ){ - *(sxi32 *)pOutVal = 0; - } - return SXERR_EMPTY; - } -#endif - zEnd = &zSrc[nLen]; - while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ - isNeg = (zSrc[0] == '-') ? TRUE :FALSE; - zSrc++; - } - /* Skip leading zero */ - while(zSrc < zEnd && zSrc[0] == '0' ){ - zSrc++; - } - zIn = zSrc; - for(;;){ - if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; - if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; - if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; - if(zSrc >= zEnd || !SyisDigit(zSrc[0])){ break; } if( (c=zSrc[0]-'0') > 7 || (int)(zSrc-zIn) > 20){ break;} nVal = nVal * 8 + c; zSrc++; - } - /* Skip trailing spaces */ - while(zSrc < zEnd && SyisSpace(zSrc[0])){ - zSrc++; - } - if( zRest ){ - *zRest = zSrc; - } - if( pOutVal ){ - if( isNeg == TRUE && nVal != 0 ){ - nVal = -nVal; - } - *(sxi64 *)pOutVal = nVal; - } - return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; -} -JX9_PRIVATE sxi32 SyBinaryStrToInt64(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest) -{ - const char *zIn, *zEnd; - int isNeg = FALSE; - sxi64 nVal = 0; - int c; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zSrc) ){ - if( pOutVal ){ - *(sxi32 *)pOutVal = 0; - } - return SXERR_EMPTY; - } -#endif - zEnd = &zSrc[nLen]; - while(zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+' ) ){ - isNeg = (zSrc[0] == '-') ? TRUE :FALSE; - zSrc++; - } - if( zSrc < &zEnd[-2] && zSrc[0] == '0' && (zSrc[1] == 'b' || zSrc[1] == 'B') ){ - /* Bypass binary prefix */ - zSrc += sizeof(char) * 2; - } - /* Skip leading zero */ - while(zSrc < zEnd && zSrc[0] == '0' ){ - zSrc++; - } - zIn = zSrc; - for(;;){ - if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; - if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; - if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; - if(zSrc >= zEnd || (zSrc[0] != '1' && zSrc[0] != '0') || (int)(zSrc-zIn) > 62){ break; } c = zSrc[0] - '0'; nVal = (nVal << 1) + c; zSrc++; - } - /* Skip trailing spaces */ - while(zSrc < zEnd && SyisSpace(zSrc[0])){ - zSrc++; - } - if( zRest ){ - *zRest = zSrc; - } - if( pOutVal ){ - if( isNeg == TRUE && nVal != 0 ){ - nVal = -nVal; - } - *(sxi64 *)pOutVal = nVal; - } - return (zSrc >= zEnd) ? SXRET_OK : SXERR_SYNTAX; -} -JX9_PRIVATE sxi32 SyStrToReal(const char *zSrc, sxu32 nLen, void * pOutVal, const char **zRest) -{ -#define SXDBL_DIG 15 -#define SXDBL_MAX_EXP 308 -#define SXDBL_MIN_EXP_PLUS 307 - static const sxreal aTab[] = { - 10, - 1.0e2, - 1.0e4, - 1.0e8, - 1.0e16, - 1.0e32, - 1.0e64, - 1.0e128, - 1.0e256 - }; - sxu8 neg = FALSE; - sxreal Val = 0.0; - const char *zEnd; - sxi32 Lim, exp; - sxreal *p = 0; -#ifdef UNTRUST - if( SX_EMPTY_STR(zSrc) ){ - if( pOutVal ){ - *(sxreal *)pOutVal = 0.0; - } - return SXERR_EMPTY; - } -#endif - zEnd = &zSrc[nLen]; - while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zSrc < zEnd && (zSrc[0] == '-' || zSrc[0] == '+' ) ){ - neg = zSrc[0] == '-' ? TRUE : FALSE ; - zSrc++; - } - Lim = SXDBL_DIG ; - for(;;){ - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; zSrc++ ; --Lim; - } - if( zSrc < zEnd && ( zSrc[0] == '.' || zSrc[0] == ',' ) ){ - sxreal dec = 1.0; - zSrc++; - for(;;){ - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; - if(zSrc >= zEnd||!Lim||!SyisDigit(zSrc[0])) break ; Val = Val * 10.0 + (zSrc[0] - '0') ; dec *= 10.0; zSrc++ ;--Lim; - } - Val /= dec; - } - if( neg == TRUE && Val != 0.0 ) { - Val = -Val ; - } - if( Lim <= 0 ){ - /* jump overflow digit */ - while( zSrc < zEnd ){ - if( zSrc[0] == 'e' || zSrc[0] == 'E' ){ - break; - } - zSrc++; - } - } - neg = FALSE; - if( zSrc < zEnd && ( zSrc[0] == 'e' || zSrc[0] == 'E' ) ){ - zSrc++; - if( zSrc < zEnd && ( zSrc[0] == '-' || zSrc[0] == '+') ){ - neg = zSrc[0] == '-' ? TRUE : FALSE ; - zSrc++; - } - exp = 0; - while( zSrc < zEnd && SyisDigit(zSrc[0]) && exp < SXDBL_MAX_EXP ){ - exp = exp * 10 + (zSrc[0] - '0'); - zSrc++; - } - if( neg ){ - if( exp > SXDBL_MIN_EXP_PLUS ) exp = SXDBL_MIN_EXP_PLUS ; - }else if ( exp > SXDBL_MAX_EXP ){ - exp = SXDBL_MAX_EXP; - } - for( p = (sxreal *)aTab ; exp ; exp >>= 1 , p++ ){ - if( exp & 01 ){ - if( neg ){ - Val /= *p ; - }else{ - Val *= *p; - } - } - } - } - while( zSrc < zEnd && SyisSpace(zSrc[0]) ){ - zSrc++; - } - if( zRest ){ - *zRest = zSrc; - } - if( pOutVal ){ - *(sxreal *)pOutVal = Val; - } - return zSrc >= zEnd ? SXRET_OK : SXERR_SYNTAX; -} -/* SyRunTimeApi:sxlib.c */ -JX9_PRIVATE sxu32 SyBinHash(const void *pSrc, sxu32 nLen) -{ - register unsigned char *zIn = (unsigned char *)pSrc; - unsigned char *zEnd; - sxu32 nH = 5381; - zEnd = &zIn[nLen]; - for(;;){ - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - } - return nH; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyBase64Encode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData) -{ - static const unsigned char zBase64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - unsigned char *zIn = (unsigned char *)zSrc; - unsigned char z64[4]; - sxu32 i; - sxi32 rc; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zSrc) || xConsumer == 0){ - return SXERR_EMPTY; - } -#endif - for(i = 0; i + 2 < nLen; i += 3){ - z64[0] = zBase64[(zIn[i] >> 2) & 0x3F]; - z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F]; - z64[2] = zBase64[( ((zIn[i+1] & 0x0F) << 2) | (zIn[i + 2] >> 6) ) & 0x3F]; - z64[3] = zBase64[ zIn[i + 2] & 0x3F]; - - rc = xConsumer((const void *)z64, sizeof(z64), pUserData); - if( rc != SXRET_OK ){return SXERR_ABORT;} - - } - if ( i+1 < nLen ){ - z64[0] = zBase64[(zIn[i] >> 2) & 0x3F]; - z64[1] = zBase64[( ((zIn[i] & 0x03) << 4) | (zIn[i+1] >> 4)) & 0x3F]; - z64[2] = zBase64[(zIn[i+1] & 0x0F) << 2 ]; - z64[3] = '='; - - rc = xConsumer((const void *)z64, sizeof(z64), pUserData); - if( rc != SXRET_OK ){return SXERR_ABORT;} - - }else if( i < nLen ){ - z64[0] = zBase64[(zIn[i] >> 2) & 0x3F]; - z64[1] = zBase64[(zIn[i] & 0x03) << 4]; - z64[2] = '='; - z64[3] = '='; - - rc = xConsumer((const void *)z64, sizeof(z64), pUserData); - if( rc != SXRET_OK ){return SXERR_ABORT;} - } - - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyBase64Decode(const char *zB64, sxu32 nLen, ProcConsumer xConsumer, void *pUserData) -{ - static const sxu32 aBase64Trans[] = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 62, 0, 0, 0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, - 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, - 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 0, 0, - 0, 0, 0 - }; - sxu32 n, w, x, y, z; - sxi32 rc; - unsigned char zOut[10]; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zB64) || xConsumer == 0 ){ - return SXERR_EMPTY; - } -#endif - while(nLen > 0 && zB64[nLen - 1] == '=' ){ - nLen--; - } - for( n = 0 ; n+3>4) & 0x03); - zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F); - zOut[2] = ((y<<6) & 0xC0) | (z & 0x3F); - - rc = xConsumer((const void *)zOut, sizeof(unsigned char)*3, pUserData); - if( rc != SXRET_OK ){ return SXERR_ABORT;} - } - if( n+2 < nLen ){ - w = aBase64Trans[zB64[n] & 0x7F]; - x = aBase64Trans[zB64[n+1] & 0x7F]; - y = aBase64Trans[zB64[n+2] & 0x7F]; - - zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03); - zOut[1] = ((x<<4) & 0xF0) | ((y>>2) & 0x0F); - - rc = xConsumer((const void *)zOut, sizeof(unsigned char)*2, pUserData); - if( rc != SXRET_OK ){ return SXERR_ABORT;} - }else if( n+1 < nLen ){ - w = aBase64Trans[zB64[n] & 0x7F]; - x = aBase64Trans[zB64[n+1] & 0x7F]; - - zOut[0] = ((w<<2) & 0xFC) | ((x>>4) & 0x03); - - rc = xConsumer((const void *)zOut, sizeof(unsigned char)*1, pUserData); - if( rc != SXRET_OK ){ return SXERR_ABORT;} - } - return SXRET_OK; -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -#define INVALID_LEXER(LEX) ( LEX == 0 || LEX->xTokenizer == 0 ) -JX9_PRIVATE sxi32 SyLexInit(SyLex *pLex, SySet *pSet, ProcTokenizer xTokenizer, void *pUserData) -{ - SyStream *pStream; -#if defined (UNTRUST) - if ( pLex == 0 || xTokenizer == 0 ){ - return SXERR_CORRUPT; - } -#endif - pLex->pTokenSet = 0; - /* Initialize lexer fields */ - if( pSet ){ - if ( SySetElemSize(pSet) != sizeof(SyToken) ){ - return SXERR_INVALID; - } - pLex->pTokenSet = pSet; - } - pStream = &pLex->sStream; - pLex->xTokenizer = xTokenizer; - pLex->pUserData = pUserData; - - pStream->nLine = 1; - pStream->nIgn = 0; - pStream->zText = pStream->zEnd = 0; - pStream->pSet = pSet; - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyLexTokenizeInput(SyLex *pLex, const char *zInput, sxu32 nLen, void *pCtxData, ProcSort xSort, ProcCmp xCmp) -{ - const unsigned char *zCur; - SyStream *pStream; - SyToken sToken; - sxi32 rc; -#if defined (UNTRUST) - if ( INVALID_LEXER(pLex) || zInput == 0 ){ - return SXERR_CORRUPT; - } -#endif - pStream = &pLex->sStream; - /* Point to the head of the input */ - pStream->zText = pStream->zInput = (const unsigned char *)zInput; - /* Point to the end of the input */ - pStream->zEnd = &pStream->zInput[nLen]; - for(;;){ - if( pStream->zText >= pStream->zEnd ){ - /* End of the input reached */ - break; - } - zCur = pStream->zText; - /* Call the tokenizer callback */ - rc = pLex->xTokenizer(pStream, &sToken, pLex->pUserData, pCtxData); - if( rc != SXRET_OK && rc != SXERR_CONTINUE ){ - /* Tokenizer callback request an operation abort */ - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - break; - } - if( rc == SXERR_CONTINUE ){ - /* Request to ignore this token */ - pStream->nIgn++; - }else if( pLex->pTokenSet ){ - /* Put the token in the set */ - rc = SySetPut(pLex->pTokenSet, (const void *)&sToken); - if( rc != SXRET_OK ){ - break; - } - } - if( zCur >= pStream->zText ){ - /* Automatic advance of the stream cursor */ - pStream->zText = &zCur[1]; - } - } - if( xSort && pLex->pTokenSet ){ - SyToken *aToken = (SyToken *)SySetBasePtr(pLex->pTokenSet); - /* Sort the extrated tokens */ - if( xCmp == 0 ){ - /* Use a default comparison function */ - xCmp = SyMemcmp; - } - xSort(aToken, SySetUsed(pLex->pTokenSet), sizeof(SyToken), xCmp); - } - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyLexRelease(SyLex *pLex) -{ - sxi32 rc = SXRET_OK; -#if defined (UNTRUST) - if ( INVALID_LEXER(pLex) ){ - return SXERR_CORRUPT; - } -#else - SXUNUSED(pLex); /* Prevent compiler warning */ -#endif - return rc; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -#define SAFE_HTTP(C) (SyisAlphaNum(c) || c == '_' || c == '-' || c == '$' || c == '.' ) -JX9_PRIVATE sxi32 SyUriEncode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData) -{ - unsigned char *zIn = (unsigned char *)zSrc; - unsigned char zHex[3] = { '%', 0, 0 }; - unsigned char zOut[2]; - unsigned char *zCur, *zEnd; - sxi32 c; - sxi32 rc; -#ifdef UNTRUST - if( SX_EMPTY_STR(zSrc) || xConsumer == 0 ){ - return SXERR_EMPTY; - } -#endif - rc = SXRET_OK; - zEnd = &zIn[nLen]; zCur = zIn; - for(;;){ - if( zCur >= zEnd ){ - if( zCur != zIn ){ - rc = xConsumer(zIn, (sxu32)(zCur-zIn), pUserData); - } - break; - } - c = zCur[0]; - if( SAFE_HTTP(c) ){ - zCur++; continue; - } - if( zCur != zIn && SXRET_OK != (rc = xConsumer(zIn, (sxu32)(zCur-zIn), pUserData))){ - break; - } - if( c == ' ' ){ - zOut[0] = '+'; - rc = xConsumer((const void *)zOut, sizeof(unsigned char), pUserData); - }else{ - zHex[1] = "0123456789ABCDEF"[(c >> 4) & 0x0F]; - zHex[2] = "0123456789ABCDEF"[c & 0x0F]; - rc = xConsumer(zHex, sizeof(zHex), pUserData); - } - if( SXRET_OK != rc ){ - break; - } - zIn = &zCur[1]; zCur = zIn ; - } - return rc == SXRET_OK ? SXRET_OK : SXERR_ABORT; -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -static sxi32 SyAsciiToHex(sxi32 c) -{ - if( c >= 'a' && c <= 'f' ){ - c += 10 - 'a'; - return c; - } - if( c >= '0' && c <= '9' ){ - c -= '0'; - return c; - } - if( c >= 'A' && c <= 'F') { - c += 10 - 'A'; - return c; - } - return 0; -} -JX9_PRIVATE sxi32 SyUriDecode(const char *zSrc, sxu32 nLen, ProcConsumer xConsumer, void *pUserData, int bUTF8) -{ - static const sxu8 Utf8Trans[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00 - }; - const char *zIn = zSrc; - const char *zEnd; - const char *zCur; - sxu8 *zOutPtr; - sxu8 zOut[10]; - sxi32 c, d; - sxi32 rc; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zSrc) || xConsumer == 0 ){ - return SXERR_EMPTY; - } -#endif - rc = SXRET_OK; - zEnd = &zSrc[nLen]; - zCur = zIn; - for(;;){ - while(zCur < zEnd && zCur[0] != '%' && zCur[0] != '+' ){ - zCur++; - } - if( zCur != zIn ){ - /* Consume input */ - rc = xConsumer(zIn, (unsigned int)(zCur-zIn), pUserData); - if( rc != SXRET_OK ){ - /* User consumer routine request an operation abort */ - break; - } - } - if( zCur >= zEnd ){ - rc = SXRET_OK; - break; - } - /* Decode unsafe HTTP characters */ - zOutPtr = zOut; - if( zCur[0] == '+' ){ - *zOutPtr++ = ' '; - zCur++; - }else{ - if( &zCur[2] >= zEnd ){ - rc = SXERR_OVERFLOW; - break; - } - c = (SyAsciiToHex(zCur[1]) <<4) | SyAsciiToHex(zCur[2]); - zCur += 3; - if( c < 0x000C0 ){ - *zOutPtr++ = (sxu8)c; - }else{ - c = Utf8Trans[c-0xC0]; - while( zCur[0] == '%' ){ - d = (SyAsciiToHex(zCur[1]) <<4) | SyAsciiToHex(zCur[2]); - if( (d&0xC0) != 0x80 ){ - break; - } - c = (c<<6) + (0x3f & d); - zCur += 3; - } - if( bUTF8 == FALSE ){ - *zOutPtr++ = (sxu8)c; - }else{ - SX_WRITE_UTF8(zOutPtr, c); - } - } - - } - /* Consume the decoded characters */ - rc = xConsumer((const void *)zOut, (unsigned int)(zOutPtr-zOut), pUserData); - if( rc != SXRET_OK ){ - break; - } - /* Synchronize pointers */ - zIn = zCur; - } - return rc; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -static const char *zEngDay[] = { - "Sunday", "Monday", "Tuesday", "Wednesday", - "Thursday", "Friday", "Saturday" -}; -static const char *zEngMonth[] = { - "January", "February", "March", "April", - "May", "June", "July", "August", - "September", "October", "November", "December" -}; -static const char * GetDay(sxi32 i) -{ - return zEngDay[ i % 7 ]; -} -static const char * GetMonth(sxi32 i) -{ - return zEngMonth[ i % 12 ]; -} -JX9_PRIVATE const char * SyTimeGetDay(sxi32 iDay) -{ - return GetDay(iDay); -} -JX9_PRIVATE const char * SyTimeGetMonth(sxi32 iMonth) -{ - return GetMonth(iMonth); -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* SyRunTimeApi: sxfmt.c */ -#define SXFMT_BUFSIZ 1024 /* Conversion buffer size */ -/* -** Conversion types fall into various categories as defined by the -** following enumeration. -*/ -#define SXFMT_RADIX 1 /* Integer types.%d, %x, %o, and so forth */ -#define SXFMT_FLOAT 2 /* Floating point.%f */ -#define SXFMT_EXP 3 /* Exponentional notation.%e and %E */ -#define SXFMT_GENERIC 4 /* Floating or exponential, depending on exponent.%g */ -#define SXFMT_SIZE 5 /* Total number of characters processed so far.%n */ -#define SXFMT_STRING 6 /* Strings.%s */ -#define SXFMT_PERCENT 7 /* Percent symbol.%% */ -#define SXFMT_CHARX 8 /* Characters.%c */ -#define SXFMT_ERROR 9 /* Used to indicate no such conversion type */ -/* Extension by Symisc Systems */ -#define SXFMT_RAWSTR 13 /* %z Pointer to raw string (SyString *) */ -#define SXFMT_UNUSED 15 -/* -** Allowed values for SyFmtInfo.flags -*/ -#define SXFLAG_SIGNED 0x01 -#define SXFLAG_UNSIGNED 0x02 -/* Allowed values for SyFmtConsumer.nType */ -#define SXFMT_CONS_PROC 1 /* Consumer is a procedure */ -#define SXFMT_CONS_STR 2 /* Consumer is a managed string */ -#define SXFMT_CONS_FILE 5 /* Consumer is an open File */ -#define SXFMT_CONS_BLOB 6 /* Consumer is a BLOB */ -/* -** Each builtin conversion character (ex: the 'd' in "%d") is described -** by an instance of the following structure -*/ -typedef struct SyFmtInfo SyFmtInfo; -struct SyFmtInfo -{ - char fmttype; /* The format field code letter [i.e: 'd', 's', 'x'] */ - sxu8 base; /* The base for radix conversion */ - int flags; /* One or more of SXFLAG_ constants below */ - sxu8 type; /* Conversion paradigm */ - char *charset; /* The character set for conversion */ - char *prefix; /* Prefix on non-zero values in alt format */ -}; -typedef struct SyFmtConsumer SyFmtConsumer; -struct SyFmtConsumer -{ - sxu32 nLen; /* Total output length */ - sxi32 nType; /* Type of the consumer see below */ - sxi32 rc; /* Consumer return value;Abort processing if rc != SXRET_OK */ - union{ - struct{ - ProcConsumer xUserConsumer; - void *pUserData; - }sFunc; - SyBlob *pBlob; - }uConsumer; -}; -#ifndef SX_OMIT_FLOATINGPOINT -static int getdigit(sxlongreal *val, int *cnt) -{ - sxlongreal d; - int digit; - - if( (*cnt)++ >= 16 ){ - return '0'; - } - digit = (int)*val; - d = digit; - *val = (*val - d)*10.0; - return digit + '0' ; -} -#endif /* SX_OMIT_FLOATINGPOINT */ -/* - * The following routine was taken from the SQLITE2 source tree and was - * extended by Symisc Systems to fit its need. - * Status: Public Domain - */ -static sxi32 InternFormat(ProcConsumer xConsumer, void *pUserData, const char *zFormat, va_list ap) -{ - /* - * The following table is searched linearly, so it is good to put the most frequently - * used conversion types first. - */ -static const SyFmtInfo aFmt[] = { - { 'd', 10, SXFLAG_SIGNED, SXFMT_RADIX, "0123456789", 0 }, - { 's', 0, 0, SXFMT_STRING, 0, 0 }, - { 'c', 0, 0, SXFMT_CHARX, 0, 0 }, - { 'x', 16, 0, SXFMT_RADIX, "0123456789abcdef", "x0" }, - { 'X', 16, 0, SXFMT_RADIX, "0123456789ABCDEF", "X0" }, - /* -- Extensions by Symisc Systems -- */ - { 'z', 0, 0, SXFMT_RAWSTR, 0, 0 }, /* Pointer to a raw string (SyString *) */ - { 'B', 2, 0, SXFMT_RADIX, "01", "b0"}, - /* -- End of Extensions -- */ - { 'o', 8, 0, SXFMT_RADIX, "01234567", "0" }, - { 'u', 10, 0, SXFMT_RADIX, "0123456789", 0 }, -#ifndef SX_OMIT_FLOATINGPOINT - { 'f', 0, SXFLAG_SIGNED, SXFMT_FLOAT, 0, 0 }, - { 'e', 0, SXFLAG_SIGNED, SXFMT_EXP, "e", 0 }, - { 'E', 0, SXFLAG_SIGNED, SXFMT_EXP, "E", 0 }, - { 'g', 0, SXFLAG_SIGNED, SXFMT_GENERIC, "e", 0 }, - { 'G', 0, SXFLAG_SIGNED, SXFMT_GENERIC, "E", 0 }, -#endif - { 'i', 10, SXFLAG_SIGNED, SXFMT_RADIX, "0123456789", 0 }, - { 'n', 0, 0, SXFMT_SIZE, 0, 0 }, - { '%', 0, 0, SXFMT_PERCENT, 0, 0 }, - { 'p', 10, 0, SXFMT_RADIX, "0123456789", 0 } -}; - int c; /* Next character in the format string */ - char *bufpt; /* Pointer to the conversion buffer */ - int precision; /* Precision of the current field */ - int length; /* Length of the field */ - int idx; /* A general purpose loop counter */ - int width; /* Width of the current field */ - sxu8 flag_leftjustify; /* True if "-" flag is present */ - sxu8 flag_plussign; /* True if "+" flag is present */ - sxu8 flag_blanksign; /* True if " " flag is present */ - sxu8 flag_alternateform; /* True if "#" flag is present */ - sxu8 flag_zeropad; /* True if field width constant starts with zero */ - sxu8 flag_long; /* True if "l" flag is present */ - sxi64 longvalue; /* Value for integer types */ - const SyFmtInfo *infop; /* Pointer to the appropriate info structure */ - char buf[SXFMT_BUFSIZ]; /* Conversion buffer */ - char prefix; /* Prefix character."+" or "-" or " " or '\0'.*/ - sxu8 errorflag = 0; /* True if an error is encountered */ - sxu8 xtype; /* Conversion paradigm */ - char *zExtra; - static char spaces[] = " "; -#define etSPACESIZE ((int)sizeof(spaces)-1) -#ifndef SX_OMIT_FLOATINGPOINT - sxlongreal realvalue; /* Value for real types */ - int exp; /* exponent of real numbers */ - double rounder; /* Used for rounding floating point values */ - sxu8 flag_dp; /* True if decimal point should be shown */ - sxu8 flag_rtz; /* True if trailing zeros should be removed */ - sxu8 flag_exp; /* True to force display of the exponent */ - int nsd; /* Number of significant digits returned */ -#endif - int rc; - - length = 0; - bufpt = 0; - for(; (c=(*zFormat))!=0; ++zFormat){ - if( c!='%' ){ - unsigned int amt; - bufpt = (char *)zFormat; - amt = 1; - while( (c=(*++zFormat))!='%' && c!=0 ) amt++; - rc = xConsumer((const void *)bufpt, amt, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - if( c==0 ){ - return errorflag > 0 ? SXERR_FORMAT : SXRET_OK; - } - } - if( (c=(*++zFormat))==0 ){ - errorflag = 1; - rc = xConsumer("%", sizeof("%")-1, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - return errorflag > 0 ? SXERR_FORMAT : SXRET_OK; - } - /* Find out what flags are present */ - flag_leftjustify = flag_plussign = flag_blanksign = - flag_alternateform = flag_zeropad = 0; - do{ - switch( c ){ - case '-': flag_leftjustify = 1; c = 0; break; - case '+': flag_plussign = 1; c = 0; break; - case ' ': flag_blanksign = 1; c = 0; break; - case '#': flag_alternateform = 1; c = 0; break; - case '0': flag_zeropad = 1; c = 0; break; - default: break; - } - }while( c==0 && (c=(*++zFormat))!=0 ); - /* Get the field width */ - width = 0; - if( c=='*' ){ - width = va_arg(ap, int); - if( width<0 ){ - flag_leftjustify = 1; - width = -width; - } - c = *++zFormat; - }else{ - while( c>='0' && c<='9' ){ - width = width*10 + c - '0'; - c = *++zFormat; - } - } - if( width > SXFMT_BUFSIZ-10 ){ - width = SXFMT_BUFSIZ-10; - } - /* Get the precision */ - precision = -1; - if( c=='.' ){ - precision = 0; - c = *++zFormat; - if( c=='*' ){ - precision = va_arg(ap, int); - if( precision<0 ) precision = -precision; - c = *++zFormat; - }else{ - while( c>='0' && c<='9' ){ - precision = precision*10 + c - '0'; - c = *++zFormat; - } - } - } - /* Get the conversion type modifier */ - flag_long = 0; - if( c=='l' || c == 'q' /* BSD quad (expect a 64-bit integer) */ ){ - flag_long = (c == 'q') ? 2 : 1; - c = *++zFormat; - if( c == 'l' ){ - /* Standard printf emulation 'lld' (expect a 64bit integer) */ - flag_long = 2; - } - } - /* Fetch the info entry for the field */ - infop = 0; - xtype = SXFMT_ERROR; - for(idx=0; idx< (int)SX_ARRAYSIZE(aFmt); idx++){ - if( c==aFmt[idx].fmttype ){ - infop = &aFmt[idx]; - xtype = infop->type; - break; - } - } - zExtra = 0; - - /* - ** At this point, variables are initialized as follows: - ** - ** flag_alternateform TRUE if a '#' is present. - ** flag_plussign TRUE if a '+' is present. - ** flag_leftjustify TRUE if a '-' is present or if the - ** field width was negative. - ** flag_zeropad TRUE if the width began with 0. - ** flag_long TRUE if the letter 'l' (ell) or 'q'(BSD quad) prefixed - ** the conversion character. - ** flag_blanksign TRUE if a ' ' is present. - ** width The specified field width.This is - ** always non-negative.Zero is the default. - ** precision The specified precision.The default - ** is -1. - ** xtype The object of the conversion. - ** infop Pointer to the appropriate info struct. - */ - switch( xtype ){ - case SXFMT_RADIX: - if( flag_long > 0 ){ - if( flag_long > 1 ){ - /* BSD quad: expect a 64-bit integer */ - longvalue = va_arg(ap, sxi64); - }else{ - longvalue = va_arg(ap, sxlong); - } - }else{ - if( infop->flags & SXFLAG_SIGNED ){ - longvalue = va_arg(ap, sxi32); - }else{ - longvalue = va_arg(ap, sxu32); - } - } - /* Limit the precision to prevent overflowing buf[] during conversion */ - if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40; -#if 1 - /* For the format %#x, the value zero is printed "0" not "0x0". - ** I think this is stupid.*/ - if( longvalue==0 ) flag_alternateform = 0; -#else - /* More sensible: turn off the prefix for octal (to prevent "00"), - ** but leave the prefix for hex.*/ - if( longvalue==0 && infop->base==8 ) flag_alternateform = 0; -#endif - if( infop->flags & SXFLAG_SIGNED ){ - if( longvalue<0 ){ - longvalue = -longvalue; - /* Ticket 1433-003 */ - if( longvalue < 0 ){ - /* Overflow */ - longvalue= 0x7FFFFFFFFFFFFFFF; - } - prefix = '-'; - }else if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; - }else{ - if( longvalue<0 ){ - longvalue = -longvalue; - /* Ticket 1433-003 */ - if( longvalue < 0 ){ - /* Overflow */ - longvalue= 0x7FFFFFFFFFFFFFFF; - } - } - prefix = 0; - } - if( flag_zeropad && precisioncharset; - base = infop->base; - do{ /* Convert to ascii */ - *(--bufpt) = cset[longvalue%base]; - longvalue = longvalue/base; - }while( longvalue>0 ); - } - length = &buf[SXFMT_BUFSIZ-1]-bufpt; - for(idx=precision-length; idx>0; idx--){ - *(--bufpt) = '0'; /* Zero pad */ - } - if( prefix ) *(--bufpt) = prefix; /* Add sign */ - if( flag_alternateform && infop->prefix ){ /* Add "0" or "0x" */ - char *pre, x; - pre = infop->prefix; - if( *bufpt!=pre[0] ){ - for(pre=infop->prefix; (x=(*pre))!=0; pre++) *(--bufpt) = x; - } - } - length = &buf[SXFMT_BUFSIZ-1]-bufpt; - break; - case SXFMT_FLOAT: - case SXFMT_EXP: - case SXFMT_GENERIC: -#ifndef SX_OMIT_FLOATINGPOINT - realvalue = va_arg(ap, double); - if( precision<0 ) precision = 6; /* Set default precision */ - if( precision>SXFMT_BUFSIZ-40) precision = SXFMT_BUFSIZ-40; - if( realvalue<0.0 ){ - realvalue = -realvalue; - prefix = '-'; - }else{ - if( flag_plussign ) prefix = '+'; - else if( flag_blanksign ) prefix = ' '; - else prefix = 0; - } - if( infop->type==SXFMT_GENERIC && precision>0 ) precision--; - rounder = 0.0; -#if 0 - /* Rounding works like BSD when the constant 0.4999 is used.Wierd! */ - for(idx=precision, rounder=0.4999; idx>0; idx--, rounder*=0.1); -#else - /* It makes more sense to use 0.5 */ - for(idx=precision, rounder=0.5; idx>0; idx--, rounder*=0.1); -#endif - if( infop->type==SXFMT_FLOAT ) realvalue += rounder; - /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ - exp = 0; - if( realvalue>0.0 ){ - while( realvalue>=1e8 && exp<=350 ){ realvalue *= 1e-8; exp+=8; } - while( realvalue>=10.0 && exp<=350 ){ realvalue *= 0.1; exp++; } - while( realvalue<1e-8 && exp>=-350 ){ realvalue *= 1e8; exp-=8; } - while( realvalue<1.0 && exp>=-350 ){ realvalue *= 10.0; exp--; } - if( exp>350 || exp<-350 ){ - bufpt = "NaN"; - length = 3; - break; - } - } - bufpt = buf; - /* - ** If the field type is etGENERIC, then convert to either etEXP - ** or etFLOAT, as appropriate. - */ - flag_exp = xtype==SXFMT_EXP; - if( xtype!=SXFMT_FLOAT ){ - realvalue += rounder; - if( realvalue>=10.0 ){ realvalue *= 0.1; exp++; } - } - if( xtype==SXFMT_GENERIC ){ - flag_rtz = !flag_alternateform; - if( exp<-4 || exp>precision ){ - xtype = SXFMT_EXP; - }else{ - precision = precision - exp; - xtype = SXFMT_FLOAT; - } - }else{ - flag_rtz = 0; - } - /* - ** The "exp+precision" test causes output to be of type etEXP if - ** the precision is too large to fit in buf[]. - */ - nsd = 0; - if( xtype==SXFMT_FLOAT && exp+precision0 || flag_alternateform); - if( prefix ) *(bufpt++) = prefix; /* Sign */ - if( exp<0 ) *(bufpt++) = '0'; /* Digits before "." */ - else for(; exp>=0; exp--) *(bufpt++) = (char)getdigit(&realvalue, &nsd); - if( flag_dp ) *(bufpt++) = '.'; /* The decimal point */ - for(exp++; exp<0 && precision>0; precision--, exp++){ - *(bufpt++) = '0'; - } - while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue, &nsd); - *(bufpt--) = 0; /* Null terminate */ - if( flag_rtz && flag_dp ){ /* Remove trailing zeros and "." */ - while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; - if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; - } - bufpt++; /* point to next free slot */ - }else{ /* etEXP or etGENERIC */ - flag_dp = (precision>0 || flag_alternateform); - if( prefix ) *(bufpt++) = prefix; /* Sign */ - *(bufpt++) = (char)getdigit(&realvalue, &nsd); /* First digit */ - if( flag_dp ) *(bufpt++) = '.'; /* Decimal point */ - while( (precision--)>0 ) *(bufpt++) = (char)getdigit(&realvalue, &nsd); - bufpt--; /* point to last digit */ - if( flag_rtz && flag_dp ){ /* Remove tail zeros */ - while( bufpt>=buf && *bufpt=='0' ) *(bufpt--) = 0; - if( bufpt>=buf && *bufpt=='.' ) *(bufpt--) = 0; - } - bufpt++; /* point to next free slot */ - if( exp || flag_exp ){ - *(bufpt++) = infop->charset[0]; - if( exp<0 ){ *(bufpt++) = '-'; exp = -exp; } /* sign of exp */ - else { *(bufpt++) = '+'; } - if( exp>=100 ){ - *(bufpt++) = (char)((exp/100)+'0'); /* 100's digit */ - exp %= 100; - } - *(bufpt++) = (char)(exp/10+'0'); /* 10's digit */ - *(bufpt++) = (char)(exp%10+'0'); /* 1's digit */ - } - } - /* The converted number is in buf[] and zero terminated.Output it. - ** Note that the number is in the usual order, not reversed as with - ** integer conversions.*/ - length = bufpt-buf; - bufpt = buf; - - /* Special case: Add leading zeros if the flag_zeropad flag is - ** set and we are not left justified */ - if( flag_zeropad && !flag_leftjustify && length < width){ - int i; - int nPad = width - length; - for(i=width; i>=nPad; i--){ - bufpt[i] = bufpt[i-nPad]; - } - i = prefix!=0; - while( nPad-- ) bufpt[i++] = '0'; - length = width; - } -#else - bufpt = " "; - length = (int)sizeof(" ") - 1; -#endif /* SX_OMIT_FLOATINGPOINT */ - break; - case SXFMT_SIZE:{ - int *pSize = va_arg(ap, int *); - *pSize = ((SyFmtConsumer *)pUserData)->nLen; - length = width = 0; - } - break; - case SXFMT_PERCENT: - buf[0] = '%'; - bufpt = buf; - length = 1; - break; - case SXFMT_CHARX: - c = va_arg(ap, int); - buf[0] = (char)c; - /* Limit the precision to prevent overflowing buf[] during conversion */ - if( precision>SXFMT_BUFSIZ-40 ) precision = SXFMT_BUFSIZ-40; - if( precision>=0 ){ - for(idx=1; idx=0 && precisionzString == 0 ){ - bufpt = " "; - length = (int)sizeof(char); - break; - } - bufpt = (char *)pStr->zString; - length = (int)pStr->nByte; - break; - } - case SXFMT_ERROR: - buf[0] = '?'; - bufpt = buf; - length = (int)sizeof(char); - if( c==0 ) zFormat--; - break; - }/* End switch over the format type */ - /* - ** The text of the conversion is pointed to by "bufpt" and is - ** "length" characters long.The field width is "width".Do - ** the output. - */ - if( !flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - while( nspace>=etSPACESIZE ){ - rc = xConsumer(spaces, etSPACESIZE, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - nspace -= etSPACESIZE; - } - if( nspace>0 ){ - rc = xConsumer(spaces, (unsigned int)nspace, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - } - } - } - if( length>0 ){ - rc = xConsumer(bufpt, (unsigned int)length, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - } - if( flag_leftjustify ){ - register int nspace; - nspace = width-length; - if( nspace>0 ){ - while( nspace>=etSPACESIZE ){ - rc = xConsumer(spaces, etSPACESIZE, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - nspace -= etSPACESIZE; - } - if( nspace>0 ){ - rc = xConsumer(spaces, (unsigned int)nspace, pUserData); - if( rc != SXRET_OK ){ - return SXERR_ABORT; /* Consumer routine request an operation abort */ - } - } - } - } - }/* End for loop over the format string */ - return errorflag ? SXERR_FORMAT : SXRET_OK; -} -static sxi32 FormatConsumer(const void *pSrc, unsigned int nLen, void *pData) -{ - SyFmtConsumer *pConsumer = (SyFmtConsumer *)pData; - sxi32 rc = SXERR_ABORT; - switch(pConsumer->nType){ - case SXFMT_CONS_PROC: - /* User callback */ - rc = pConsumer->uConsumer.sFunc.xUserConsumer(pSrc, nLen, pConsumer->uConsumer.sFunc.pUserData); - break; - case SXFMT_CONS_BLOB: - /* Blob consumer */ - rc = SyBlobAppend(pConsumer->uConsumer.pBlob, pSrc, (sxu32)nLen); - break; - default: - /* Unknown consumer */ - break; - } - /* Update total number of bytes consumed so far */ - pConsumer->nLen += nLen; - pConsumer->rc = rc; - return rc; -} -static sxi32 FormatMount(sxi32 nType, void *pConsumer, ProcConsumer xUserCons, void *pUserData, sxu32 *pOutLen, const char *zFormat, va_list ap) -{ - SyFmtConsumer sCons; - sCons.nType = nType; - sCons.rc = SXRET_OK; - sCons.nLen = 0; - if( pOutLen ){ - *pOutLen = 0; - } - switch(nType){ - case SXFMT_CONS_PROC: -#if defined(UNTRUST) - if( xUserCons == 0 ){ - return SXERR_EMPTY; - } -#endif - sCons.uConsumer.sFunc.xUserConsumer = xUserCons; - sCons.uConsumer.sFunc.pUserData = pUserData; - break; - case SXFMT_CONS_BLOB: - sCons.uConsumer.pBlob = (SyBlob *)pConsumer; - break; - default: - return SXERR_UNKNOWN; - } - InternFormat(FormatConsumer, &sCons, zFormat, ap); - if( pOutLen ){ - *pOutLen = sCons.nLen; - } - return sCons.rc; -} -JX9_PRIVATE sxi32 SyProcFormat(ProcConsumer xConsumer, void *pData, const char *zFormat, ...) -{ - va_list ap; - sxi32 rc; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zFormat) ){ - return SXERR_EMPTY; - } -#endif - va_start(ap, zFormat); - rc = FormatMount(SXFMT_CONS_PROC, 0, xConsumer, pData, 0, zFormat, ap); - va_end(ap); - return rc; -} -JX9_PRIVATE sxu32 SyBlobFormat(SyBlob *pBlob, const char *zFormat, ...) -{ - va_list ap; - sxu32 n; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zFormat) ){ - return 0; - } -#endif - va_start(ap, zFormat); - FormatMount(SXFMT_CONS_BLOB, &(*pBlob), 0, 0, &n, zFormat, ap); - va_end(ap); - return n; -} -JX9_PRIVATE sxu32 SyBlobFormatAp(SyBlob *pBlob, const char *zFormat, va_list ap) -{ - sxu32 n = 0; /* cc warning */ -#if defined(UNTRUST) - if( SX_EMPTY_STR(zFormat) ){ - return 0; - } -#endif - FormatMount(SXFMT_CONS_BLOB, &(*pBlob), 0, 0, &n, zFormat, ap); - return n; -} -JX9_PRIVATE sxu32 SyBufferFormat(char *zBuf, sxu32 nLen, const char *zFormat, ...) -{ - SyBlob sBlob; - va_list ap; - sxu32 n; -#if defined(UNTRUST) - if( SX_EMPTY_STR(zFormat) ){ - return 0; - } -#endif - if( SXRET_OK != SyBlobInitFromBuf(&sBlob, zBuf, nLen - 1) ){ - return 0; - } - va_start(ap, zFormat); - FormatMount(SXFMT_CONS_BLOB, &sBlob, 0, 0, 0, zFormat, ap); - va_end(ap); - n = SyBlobLength(&sBlob); - /* Append the null terminator */ - sBlob.mByte++; - SyBlobAppend(&sBlob, "\0", sizeof(char)); - return n; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -/* - * Zip File Format: - * - * Byte order: Little-endian - * - * [Local file header + Compressed data [+ Extended local header]?]* - * [Central directory]* - * [End of central directory record] - * - * Local file header:* - * Offset Length Contents - * 0 4 bytes Local file header signature (0x04034b50) - * 4 2 bytes Version needed to extract - * 6 2 bytes General purpose bit flag - * 8 2 bytes Compression method - * 10 2 bytes Last mod file time - * 12 2 bytes Last mod file date - * 14 4 bytes CRC-32 - * 18 4 bytes Compressed size (n) - * 22 4 bytes Uncompressed size - * 26 2 bytes Filename length (f) - * 28 2 bytes Extra field length (e) - * 30 (f)bytes Filename - * (e)bytes Extra field - * (n)bytes Compressed data - * - * Extended local header:* - * Offset Length Contents - * 0 4 bytes Extended Local file header signature (0x08074b50) - * 4 4 bytes CRC-32 - * 8 4 bytes Compressed size - * 12 4 bytes Uncompressed size - * - * Extra field:?(if any) - * Offset Length Contents - * 0 2 bytes Header ID (0x001 until 0xfb4a) see extended appnote from Info-zip - * 2 2 bytes Data size (g) - * (g) bytes (g) bytes of extra field - * - * Central directory:* - * Offset Length Contents - * 0 4 bytes Central file header signature (0x02014b50) - * 4 2 bytes Version made by - * 6 2 bytes Version needed to extract - * 8 2 bytes General purpose bit flag - * 10 2 bytes Compression method - * 12 2 bytes Last mod file time - * 14 2 bytes Last mod file date - * 16 4 bytes CRC-32 - * 20 4 bytes Compressed size - * 24 4 bytes Uncompressed size - * 28 2 bytes Filename length (f) - * 30 2 bytes Extra field length (e) - * 32 2 bytes File comment length (c) - * 34 2 bytes Disk number start - * 36 2 bytes Internal file attributes - * 38 4 bytes External file attributes - * 42 4 bytes Relative offset of local header - * 46 (f)bytes Filename - * (e)bytes Extra field - * (c)bytes File comment - * - * End of central directory record: - * Offset Length Contents - * 0 4 bytes End of central dir signature (0x06054b50) - * 4 2 bytes Number of this disk - * 6 2 bytes Number of the disk with the start of the central directory - * 8 2 bytes Total number of entries in the central dir on this disk - * 10 2 bytes Total number of entries in the central dir - * 12 4 bytes Size of the central directory - * 16 4 bytes Offset of start of central directory with respect to the starting disk number - * 20 2 bytes zipfile comment length (c) - * 22 (c)bytes zipfile comment - * - * compression method: (2 bytes) - * 0 - The file is stored (no compression) - * 1 - The file is Shrunk - * 2 - The file is Reduced with compression factor 1 - * 3 - The file is Reduced with compression factor 2 - * 4 - The file is Reduced with compression factor 3 - * 5 - The file is Reduced with compression factor 4 - * 6 - The file is Imploded - * 7 - Reserved for Tokenizing compression algorithm - * 8 - The file is Deflated - */ - -#define SXMAKE_ZIP_WORKBUF (SXU16_HIGH/2) /* 32KB Initial working buffer size */ -#define SXMAKE_ZIP_EXTRACT_VER 0x000a /* Version needed to extract */ -#define SXMAKE_ZIP_VER 0x003 /* Version made by */ - -#define SXZIP_CENTRAL_MAGIC 0x02014b50 -#define SXZIP_END_CENTRAL_MAGIC 0x06054b50 -#define SXZIP_LOCAL_MAGIC 0x04034b50 -/*#define SXZIP_CRC32_START 0xdebb20e3*/ - -#define SXZIP_LOCAL_HDRSZ 30 /* Local header size */ -#define SXZIP_LOCAL_EXT_HDRZ 16 /* Extended local header(footer) size */ -#define SXZIP_CENTRAL_HDRSZ 46 /* Central directory header size */ -#define SXZIP_END_CENTRAL_HDRSZ 22 /* End of central directory header size */ - -#define SXARCHIVE_HASH_SIZE 64 /* Starting hash table size(MUST BE POWER OF 2)*/ -static sxi32 SyLittleEndianUnpack32(sxu32 *uNB, const unsigned char *buf, sxu32 Len) -{ - if( Len < sizeof(sxu32) ){ - return SXERR_SHORT; - } - *uNB = buf[0] + (buf[1] << 8) + (buf[2] << 16) + (buf[3] << 24); - return SXRET_OK; -} -static sxi32 SyLittleEndianUnpack16(sxu16 *pOut, const unsigned char *zBuf, sxu32 nLen) -{ - if( nLen < sizeof(sxu16) ){ - return SXERR_SHORT; - } - *pOut = zBuf[0] + (zBuf[1] <<8); - - return SXRET_OK; -} -/* - * Archive hashtable manager - */ -static sxi32 ArchiveHashGetEntry(SyArchive *pArch, const char *zName, sxu32 nLen, SyArchiveEntry **ppEntry) -{ - SyArchiveEntry *pBucketEntry; - SyString sEntry; - sxu32 nHash; - - nHash = pArch->xHash(zName, nLen); - pBucketEntry = pArch->apHash[nHash & (pArch->nSize - 1)]; - - SyStringInitFromBuf(&sEntry, zName, nLen); - - for(;;){ - if( pBucketEntry == 0 ){ - break; - } - if( nHash == pBucketEntry->nHash && pArch->xCmp(&sEntry, &pBucketEntry->sFileName) == 0 ){ - if( ppEntry ){ - *ppEntry = pBucketEntry; - } - return SXRET_OK; - } - pBucketEntry = pBucketEntry->pNextHash; - } - return SXERR_NOTFOUND; -} -static void ArchiveHashBucketInstall(SyArchiveEntry **apTable, sxu32 nBucket, SyArchiveEntry *pEntry) -{ - pEntry->pNextHash = apTable[nBucket]; - if( apTable[nBucket] != 0 ){ - apTable[nBucket]->pPrevHash = pEntry; - } - apTable[nBucket] = pEntry; -} -static sxi32 ArchiveHashGrowTable(SyArchive *pArch) -{ - sxu32 nNewSize = pArch->nSize * 2; - SyArchiveEntry **apNew; - SyArchiveEntry *pEntry; - sxu32 n; - - /* Allocate a new table */ - apNew = (SyArchiveEntry **)SyMemBackendAlloc(pArch->pAllocator, nNewSize * sizeof(SyArchiveEntry *)); - if( apNew == 0 ){ - return SXRET_OK; /* Not so fatal, simply a performance hit */ - } - SyZero(apNew, nNewSize * sizeof(SyArchiveEntry *)); - /* Rehash old entries */ - for( n = 0 , pEntry = pArch->pList ; n < pArch->nLoaded ; n++ , pEntry = pEntry->pNext ){ - pEntry->pNextHash = pEntry->pPrevHash = 0; - ArchiveHashBucketInstall(apNew, pEntry->nHash & (nNewSize - 1), pEntry); - } - /* Release the old table */ - SyMemBackendFree(pArch->pAllocator, pArch->apHash); - pArch->apHash = apNew; - pArch->nSize = nNewSize; - - return SXRET_OK; -} -static sxi32 ArchiveHashInstallEntry(SyArchive *pArch, SyArchiveEntry *pEntry) -{ - if( pArch->nLoaded > pArch->nSize * 3 ){ - ArchiveHashGrowTable(&(*pArch)); - } - pEntry->nHash = pArch->xHash(SyStringData(&pEntry->sFileName), SyStringLength(&pEntry->sFileName)); - /* Install the entry in its bucket */ - ArchiveHashBucketInstall(pArch->apHash, pEntry->nHash & (pArch->nSize - 1), pEntry); - MACRO_LD_PUSH(pArch->pList, pEntry); - pArch->nLoaded++; - - return SXRET_OK; -} - /* - * Parse the End of central directory and report status - */ - static sxi32 ParseEndOfCentralDirectory(SyArchive *pArch, const unsigned char *zBuf) - { - sxu32 nMagic = 0; /* cc -O6 warning */ - sxi32 rc; - - /* Sanity check */ - rc = SyLittleEndianUnpack32(&nMagic, zBuf, sizeof(sxu32)); - if( /* rc != SXRET_OK || */nMagic != SXZIP_END_CENTRAL_MAGIC ){ - return SXERR_CORRUPT; - } - /* # of entries */ - rc = SyLittleEndianUnpack16((sxu16 *)&pArch->nEntry, &zBuf[8], sizeof(sxu16)); - if( /* rc != SXRET_OK || */ pArch->nEntry > SXI16_HIGH /* SXU16_HIGH */ ){ - return SXERR_CORRUPT; - } - /* Size of central directory */ - rc = SyLittleEndianUnpack32(&pArch->nCentralSize, &zBuf[12], sizeof(sxu32)); - if( /*rc != SXRET_OK ||*/ pArch->nCentralSize > SXI32_HIGH ){ - return SXERR_CORRUPT; - } - /* Starting offset of central directory */ - rc = SyLittleEndianUnpack32(&pArch->nCentralOfft, &zBuf[16], sizeof(sxu32)); - if( /*rc != SXRET_OK ||*/ pArch->nCentralSize > SXI32_HIGH ){ - return SXERR_CORRUPT; - } - - return SXRET_OK; - } - /* - * Fill the zip entry with the appropriate information from the central directory - */ -static sxi32 GetCentralDirectoryEntry(SyArchive *pArch, SyArchiveEntry *pEntry, const unsigned char *zCentral, sxu32 *pNextOffset) - { - SyString *pName = &pEntry->sFileName; /* File name */ - sxu16 nDosDate, nDosTime; - sxu16 nComment = 0 ; - sxu32 nMagic = 0; /* cc -O6 warning */ - sxi32 rc; - nDosDate = nDosTime = 0; /* cc -O6 warning */ - SXUNUSED(pArch); - /* Sanity check */ - rc = SyLittleEndianUnpack32(&nMagic, zCentral, sizeof(sxu32)); - if( /* rc != SXRET_OK || */ nMagic != SXZIP_CENTRAL_MAGIC ){ - rc = SXERR_CORRUPT; - /* - * Try to recover by examing the next central directory record. - * Dont worry here, there is no risk of an infinite loop since - * the buffer size is delimited. - */ - - /* pName->nByte = 0; nComment = 0; pName->nExtra = 0 */ - goto update; - } - /* - * entry name length - */ - SyLittleEndianUnpack16((sxu16 *)&pName->nByte, &zCentral[28], sizeof(sxu16)); - if( pName->nByte > SXI16_HIGH /* SXU16_HIGH */){ - rc = SXERR_BIG; - goto update; - } - /* Extra information */ - SyLittleEndianUnpack16(&pEntry->nExtra, &zCentral[30], sizeof(sxu16)); - /* Comment length */ - SyLittleEndianUnpack16(&nComment, &zCentral[32], sizeof(sxu16)); - /* Compression method 0 == stored / 8 == deflated */ - rc = SyLittleEndianUnpack16(&pEntry->nComprMeth, &zCentral[10], sizeof(sxu16)); - /* DOS Timestamp */ - SyLittleEndianUnpack16(&nDosTime, &zCentral[12], sizeof(sxu16)); - SyLittleEndianUnpack16(&nDosDate, &zCentral[14], sizeof(sxu16)); - SyDosTimeFormat((nDosDate << 16 | nDosTime), &pEntry->sFmt); - /* Little hack to fix month index */ - pEntry->sFmt.tm_mon--; - /* CRC32 */ - rc = SyLittleEndianUnpack32(&pEntry->nCrc, &zCentral[16], sizeof(sxu32)); - /* Content size before compression */ - rc = SyLittleEndianUnpack32(&pEntry->nByte, &zCentral[24], sizeof(sxu32)); - if( pEntry->nByte > SXI32_HIGH ){ - rc = SXERR_BIG; - goto update; - } - /* - * Content size after compression. - * Note that if the file is stored pEntry->nByte should be equal to pEntry->nByteCompr - */ - rc = SyLittleEndianUnpack32(&pEntry->nByteCompr, &zCentral[20], sizeof(sxu32)); - if( pEntry->nByteCompr > SXI32_HIGH ){ - rc = SXERR_BIG; - goto update; - } - /* Finally grab the contents offset */ - SyLittleEndianUnpack32(&pEntry->nOfft, &zCentral[42], sizeof(sxu32)); - if( pEntry->nOfft > SXI32_HIGH ){ - rc = SXERR_BIG; - goto update; - } - rc = SXRET_OK; -update: - /* Update the offset to point to the next central directory record */ - *pNextOffset = SXZIP_CENTRAL_HDRSZ + pName->nByte + pEntry->nExtra + nComment; - return rc; /* Report failure or success */ -} -static sxi32 ZipFixOffset(SyArchiveEntry *pEntry, void *pSrc) -{ - sxu16 nExtra, nNameLen; - unsigned char *zHdr; - nExtra = nNameLen = 0; - zHdr = (unsigned char *)pSrc; - zHdr = &zHdr[pEntry->nOfft]; - if( SyMemcmp(zHdr, "PK\003\004", sizeof(sxu32)) != 0 ){ - return SXERR_CORRUPT; - } - SyLittleEndianUnpack16(&nNameLen, &zHdr[26], sizeof(sxu16)); - SyLittleEndianUnpack16(&nExtra, &zHdr[28], sizeof(sxu16)); - /* Fix contents offset */ - pEntry->nOfft += SXZIP_LOCAL_HDRSZ + nExtra + nNameLen; - return SXRET_OK; -} -/* - * Extract all valid entries from the central directory - */ -static sxi32 ZipExtract(SyArchive *pArch, const unsigned char *zCentral, sxu32 nLen, void *pSrc) -{ - SyArchiveEntry *pEntry, *pDup; - const unsigned char *zEnd ; /* End of central directory */ - sxu32 nIncr, nOfft; /* Central Offset */ - SyString *pName; /* Entry name */ - char *zName; - sxi32 rc; - - nOfft = nIncr = 0; - zEnd = &zCentral[nLen]; - - for(;;){ - if( &zCentral[nOfft] >= zEnd ){ - break; - } - /* Add a new entry */ - pEntry = (SyArchiveEntry *)SyMemBackendPoolAlloc(pArch->pAllocator, sizeof(SyArchiveEntry)); - if( pEntry == 0 ){ - break; - } - SyZero(pEntry, sizeof(SyArchiveEntry)); - pEntry->nMagic = SXARCH_MAGIC; - nIncr = 0; - rc = GetCentralDirectoryEntry(&(*pArch), pEntry, &zCentral[nOfft], &nIncr); - if( rc == SXRET_OK ){ - /* Fix the starting record offset so we can access entry contents correctly */ - rc = ZipFixOffset(pEntry, pSrc); - } - if(rc != SXRET_OK ){ - sxu32 nJmp = 0; - SyMemBackendPoolFree(pArch->pAllocator, pEntry); - /* Try to recover by brute-forcing for a valid central directory record */ - if( SXRET_OK == SyBlobSearch((const void *)&zCentral[nOfft + nIncr], (sxu32)(zEnd - &zCentral[nOfft + nIncr]), - (const void *)"PK\001\002", sizeof(sxu32), &nJmp)){ - nOfft += nIncr + nJmp; /* Check next entry */ - continue; - } - break; /* Giving up, archive is hopelessly corrupted */ - } - pName = &pEntry->sFileName; - pName->zString = (const char *)&zCentral[nOfft + SXZIP_CENTRAL_HDRSZ]; - if( pName->nByte <= 0 || ( pEntry->nByte <= 0 && pName->zString[pName->nByte - 1] != '/') ){ - /* Ignore zero length records (except folders) and records without names */ - SyMemBackendPoolFree(pArch->pAllocator, pEntry); - nOfft += nIncr; /* Check next entry */ - continue; - } - zName = SyMemBackendStrDup(pArch->pAllocator, pName->zString, pName->nByte); - if( zName == 0 ){ - SyMemBackendPoolFree(pArch->pAllocator, pEntry); - nOfft += nIncr; /* Check next entry */ - continue; - } - pName->zString = (const char *)zName; - /* Check for duplicates */ - rc = ArchiveHashGetEntry(&(*pArch), pName->zString, pName->nByte, &pDup); - if( rc == SXRET_OK ){ - /* Another entry with the same name exists ; link them together */ - pEntry->pNextName = pDup->pNextName; - pDup->pNextName = pEntry; - pDup->nDup++; - }else{ - /* Insert in hashtable */ - ArchiveHashInstallEntry(pArch, pEntry); - } - nOfft += nIncr; /* Check next record */ - } - pArch->pCursor = pArch->pList; - - return pArch->nLoaded > 0 ? SXRET_OK : SXERR_EMPTY; -} -JX9_PRIVATE sxi32 SyZipExtractFromBuf(SyArchive *pArch, const char *zBuf, sxu32 nLen) - { - const unsigned char *zCentral, *zEnd; - sxi32 rc; -#if defined(UNTRUST) - if( SXARCH_INVALID(pArch) || zBuf == 0 ){ - return SXERR_INVALID; - } -#endif - /* The miminal size of a zip archive: - * LOCAL_HDR_SZ + CENTRAL_HDR_SZ + END_OF_CENTRAL_HDR_SZ - * 30 46 22 - */ - if( nLen < SXZIP_LOCAL_HDRSZ + SXZIP_CENTRAL_HDRSZ + SXZIP_END_CENTRAL_HDRSZ ){ - return SXERR_CORRUPT; /* Don't bother processing return immediately */ - } - - zEnd = (unsigned char *)&zBuf[nLen - SXZIP_END_CENTRAL_HDRSZ]; - /* Find the end of central directory */ - while( ((sxu32)((unsigned char *)&zBuf[nLen] - zEnd) < (SXZIP_END_CENTRAL_HDRSZ + SXI16_HIGH)) && - zEnd > (unsigned char *)zBuf && SyMemcmp(zEnd, "PK\005\006", sizeof(sxu32)) != 0 ){ - zEnd--; - } - /* Parse the end of central directory */ - rc = ParseEndOfCentralDirectory(&(*pArch), zEnd); - if( rc != SXRET_OK ){ - return rc; - } - - /* Find the starting offset of the central directory */ - zCentral = &zEnd[-(sxi32)pArch->nCentralSize]; - if( zCentral <= (unsigned char *)zBuf || SyMemcmp(zCentral, "PK\001\002", sizeof(sxu32)) != 0 ){ - if( pArch->nCentralOfft >= nLen ){ - /* Corrupted central directory offset */ - return SXERR_CORRUPT; - } - zCentral = (unsigned char *)&zBuf[pArch->nCentralOfft]; - if( SyMemcmp(zCentral, "PK\001\002", sizeof(sxu32)) != 0 ){ - /* Corrupted zip archive */ - return SXERR_CORRUPT; - } - /* Fall thru and extract all valid entries from the central directory */ - } - rc = ZipExtract(&(*pArch), zCentral, (sxu32)(zEnd - zCentral), (void *)zBuf); - return rc; - } -/* - * Default comparison function. - */ - static sxi32 ArchiveHashCmp(const SyString *pStr1, const SyString *pStr2) - { - sxi32 rc; - rc = SyStringCmp(pStr1, pStr2, SyMemcmp); - return rc; - } -JX9_PRIVATE sxi32 SyArchiveInit(SyArchive *pArch, SyMemBackend *pAllocator, ProcHash xHash, ProcRawStrCmp xCmp) - { - SyArchiveEntry **apHash; -#if defined(UNTRUST) - if( pArch == 0 ){ - return SXERR_EMPTY; - } -#endif - SyZero(pArch, sizeof(SyArchive)); - /* Allocate a new hashtable */ - apHash = (SyArchiveEntry **)SyMemBackendAlloc(&(*pAllocator), SXARCHIVE_HASH_SIZE * sizeof(SyArchiveEntry *)); - if( apHash == 0){ - return SXERR_MEM; - } - SyZero(apHash, SXARCHIVE_HASH_SIZE * sizeof(SyArchiveEntry *)); - pArch->apHash = apHash; - pArch->xHash = xHash ? xHash : SyBinHash; - pArch->xCmp = xCmp ? xCmp : ArchiveHashCmp; - pArch->nSize = SXARCHIVE_HASH_SIZE; - pArch->pAllocator = &(*pAllocator); - pArch->nMagic = SXARCH_MAGIC; - return SXRET_OK; - } - static sxi32 ArchiveReleaseEntry(SyMemBackend *pAllocator, SyArchiveEntry *pEntry) - { - SyArchiveEntry *pDup = pEntry->pNextName; - SyArchiveEntry *pNextDup; - - /* Release duplicates first since there are not stored in the hashtable */ - for(;;){ - if( pEntry->nDup == 0 ){ - break; - } - pNextDup = pDup->pNextName; - pDup->nMagic = 0x2661; - SyMemBackendFree(pAllocator, (void *)SyStringData(&pDup->sFileName)); - SyMemBackendPoolFree(pAllocator, pDup); - pDup = pNextDup; - pEntry->nDup--; - } - pEntry->nMagic = 0x2661; - SyMemBackendFree(pAllocator, (void *)SyStringData(&pEntry->sFileName)); - SyMemBackendPoolFree(pAllocator, pEntry); - return SXRET_OK; - } -JX9_PRIVATE sxi32 SyArchiveRelease(SyArchive *pArch) - { - SyArchiveEntry *pEntry, *pNext; - pEntry = pArch->pList; - for(;;){ - if( pArch->nLoaded < 1 ){ - break; - } - pNext = pEntry->pNext; - MACRO_LD_REMOVE(pArch->pList, pEntry); - ArchiveReleaseEntry(pArch->pAllocator, pEntry); - pEntry = pNext; - pArch->nLoaded--; - } - SyMemBackendFree(pArch->pAllocator, pArch->apHash); - pArch->pCursor = 0; - pArch->nMagic = 0x2626; - return SXRET_OK; - } - JX9_PRIVATE sxi32 SyArchiveResetLoopCursor(SyArchive *pArch) - { - pArch->pCursor = pArch->pList; - return SXRET_OK; - } - JX9_PRIVATE sxi32 SyArchiveGetNextEntry(SyArchive *pArch, SyArchiveEntry **ppEntry) - { - SyArchiveEntry *pNext; - if( pArch->pCursor == 0 ){ - /* Rewind the cursor */ - pArch->pCursor = pArch->pList; - return SXERR_EOF; - } - *ppEntry = pArch->pCursor; - pNext = pArch->pCursor->pNext; - /* Advance the cursor to the next entry */ - pArch->pCursor = pNext; - return SXRET_OK; - } -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* - * Psuedo Random Number Generator (PRNG) - * @authors: SQLite authors - * @status: Public Domain - * NOTE: - * Nothing in this file or anywhere else in the library does any kind of - * encryption.The RC4 algorithm is being used as a PRNG (pseudo-random - * number generator) not as an encryption device. - */ -#define SXPRNG_MAGIC 0x13C4 -#ifdef __UNIXES__ -#include -#include -#include -#include -#include -#include -#include -#endif -static sxi32 SyOSUtilRandomSeed(void *pBuf, sxu32 nLen, void *pUnused) -{ - char *zBuf = (char *)pBuf; -#ifdef __WINNT__ - DWORD nProcessID; /* Yes, keep it uninitialized when compiling using the MinGW32 builds tools */ -#elif defined(__UNIXES__) - pid_t pid; - int fd; -#else - char zGarbage[128]; /* Yes, keep this buffer uninitialized */ -#endif - SXUNUSED(pUnused); -#ifdef __WINNT__ -#ifndef __MINGW32__ - nProcessID = GetProcessId(GetCurrentProcess()); -#endif - SyMemcpy((const void *)&nProcessID, zBuf, SXMIN(nLen, sizeof(DWORD))); - if( (sxu32)(&zBuf[nLen] - &zBuf[sizeof(DWORD)]) >= sizeof(SYSTEMTIME) ){ - GetSystemTime((LPSYSTEMTIME)&zBuf[sizeof(DWORD)]); - } -#elif defined(__UNIXES__) - fd = open("/dev/urandom", O_RDONLY); - if (fd >= 0 ){ - if( read(fd, zBuf, nLen) > 0 ){ - close(fd); - return SXRET_OK; - } - /* FALL THRU */ - close(fd); - } - pid = getpid(); - SyMemcpy((const void *)&pid, zBuf, SXMIN(nLen, sizeof(pid_t))); - if( &zBuf[nLen] - &zBuf[sizeof(pid_t)] >= (int)sizeof(struct timeval) ){ - gettimeofday((struct timeval *)&zBuf[sizeof(pid_t)], 0); - } -#else - /* Fill with uninitialized data */ - SyMemcpy(zGarbage, zBuf, SXMIN(nLen, sizeof(zGarbage))); -#endif - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyRandomnessInit(SyPRNGCtx *pCtx, ProcRandomSeed xSeed, void * pUserData) -{ - char zSeed[256]; - sxu8 t; - sxi32 rc; - sxu32 i; - if( pCtx->nMagic == SXPRNG_MAGIC ){ - return SXRET_OK; /* Already initialized */ - } - /* Initialize the state of the random number generator once, - ** the first time this routine is called.The seed value does - ** not need to contain a lot of randomness since we are not - ** trying to do secure encryption or anything like that... - */ - if( xSeed == 0 ){ - xSeed = SyOSUtilRandomSeed; - } - rc = xSeed(zSeed, sizeof(zSeed), pUserData); - if( rc != SXRET_OK ){ - return rc; - } - pCtx->i = pCtx->j = 0; - for(i=0; i < SX_ARRAYSIZE(pCtx->s) ; i++){ - pCtx->s[i] = (unsigned char)i; - } - for(i=0; i < sizeof(zSeed) ; i++){ - pCtx->j += pCtx->s[i] + zSeed[i]; - t = pCtx->s[pCtx->j]; - pCtx->s[pCtx->j] = pCtx->s[i]; - pCtx->s[i] = t; - } - pCtx->nMagic = SXPRNG_MAGIC; - - return SXRET_OK; -} -/* - * Get a single 8-bit random value using the RC4 PRNG. - */ -static sxu8 randomByte(SyPRNGCtx *pCtx) -{ - sxu8 t; - - /* Generate and return single random byte */ - pCtx->i++; - t = pCtx->s[pCtx->i]; - pCtx->j += t; - pCtx->s[pCtx->i] = pCtx->s[pCtx->j]; - pCtx->s[pCtx->j] = t; - t += pCtx->s[pCtx->i]; - return pCtx->s[t]; -} -JX9_PRIVATE sxi32 SyRandomness(SyPRNGCtx *pCtx, void *pBuf, sxu32 nLen) -{ - unsigned char *zBuf = (unsigned char *)pBuf; - unsigned char *zEnd = &zBuf[nLen]; -#if defined(UNTRUST) - if( pCtx == 0 || pBuf == 0 || nLen <= 0 ){ - return SXERR_EMPTY; - } -#endif - if(pCtx->nMagic != SXPRNG_MAGIC ){ - return SXERR_CORRUPT; - } - for(;;){ - if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; - if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; - if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; - if( zBuf >= zEnd ){break;} zBuf[0] = randomByte(pCtx); zBuf++; - } - return SXRET_OK; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_HASH_FUNC -/* SyRunTimeApi: sxhash.c */ -/* - * This code implements the MD5 message-digest algorithm. - * The algorithm is due to Ron Rivest.This code was - * written by Colin Plumb in 1993, no copyright is claimed. - * This code is in the public domain; do with it what you wish. - * - * Equivalent code is available from RSA Data Security, Inc. - * This code has been tested against that, and is equivalent, - * except that you don't need to include two pages of legalese - * with every copy. - * - * To compute the message digest of a chunk of bytes, declare an - * MD5Context structure, pass it to MD5Init, call MD5Update as - * needed on buffers full of bytes, and then call MD5Final, which - * will fill a supplied 16-byte array with the digest. - */ -#define SX_MD5_BINSZ 16 -#define SX_MD5_HEXSZ 32 -/* - * Note: this code is harmless on little-endian machines. - */ -static void byteReverse (unsigned char *buf, unsigned longs) -{ - sxu32 t; - do { - t = (sxu32)((unsigned)buf[3]<<8 | buf[2]) << 16 | - ((unsigned)buf[1]<<8 | buf[0]); - *(sxu32*)buf = t; - buf += 4; - } while (--longs); -} -/* The four core functions - F1 is optimized somewhat */ - -/* #define F1(x, y, z) (x & y | ~x & z) */ -#ifdef F1 -#undef F1 -#endif -#ifdef F2 -#undef F2 -#endif -#ifdef F3 -#undef F3 -#endif -#ifdef F4 -#undef F4 -#endif - -#define F1(x, y, z) (z ^ (x & (y ^ z))) -#define F2(x, y, z) F1(z, x, y) -#define F3(x, y, z) (x ^ y ^ z) -#define F4(x, y, z) (y ^ (x | ~z)) - -/* This is the central step in the MD5 algorithm.*/ -#define SX_MD5STEP(f, w, x, y, z, data, s) \ - ( w += f(x, y, z) + data, w = w<>(32-s), w += x ) - -/* - * The core of the MD5 algorithm, this alters an existing MD5 hash to - * reflect the addition of 16 longwords of new data.MD5Update blocks - * the data and converts bytes into longwords for this routine. - */ -static void MD5Transform(sxu32 buf[4], const sxu32 in[16]) -{ - register sxu32 a, b, c, d; - - a = buf[0]; - b = buf[1]; - c = buf[2]; - d = buf[3]; - - SX_MD5STEP(F1, a, b, c, d, in[ 0]+0xd76aa478, 7); - SX_MD5STEP(F1, d, a, b, c, in[ 1]+0xe8c7b756, 12); - SX_MD5STEP(F1, c, d, a, b, in[ 2]+0x242070db, 17); - SX_MD5STEP(F1, b, c, d, a, in[ 3]+0xc1bdceee, 22); - SX_MD5STEP(F1, a, b, c, d, in[ 4]+0xf57c0faf, 7); - SX_MD5STEP(F1, d, a, b, c, in[ 5]+0x4787c62a, 12); - SX_MD5STEP(F1, c, d, a, b, in[ 6]+0xa8304613, 17); - SX_MD5STEP(F1, b, c, d, a, in[ 7]+0xfd469501, 22); - SX_MD5STEP(F1, a, b, c, d, in[ 8]+0x698098d8, 7); - SX_MD5STEP(F1, d, a, b, c, in[ 9]+0x8b44f7af, 12); - SX_MD5STEP(F1, c, d, a, b, in[10]+0xffff5bb1, 17); - SX_MD5STEP(F1, b, c, d, a, in[11]+0x895cd7be, 22); - SX_MD5STEP(F1, a, b, c, d, in[12]+0x6b901122, 7); - SX_MD5STEP(F1, d, a, b, c, in[13]+0xfd987193, 12); - SX_MD5STEP(F1, c, d, a, b, in[14]+0xa679438e, 17); - SX_MD5STEP(F1, b, c, d, a, in[15]+0x49b40821, 22); - - SX_MD5STEP(F2, a, b, c, d, in[ 1]+0xf61e2562, 5); - SX_MD5STEP(F2, d, a, b, c, in[ 6]+0xc040b340, 9); - SX_MD5STEP(F2, c, d, a, b, in[11]+0x265e5a51, 14); - SX_MD5STEP(F2, b, c, d, a, in[ 0]+0xe9b6c7aa, 20); - SX_MD5STEP(F2, a, b, c, d, in[ 5]+0xd62f105d, 5); - SX_MD5STEP(F2, d, a, b, c, in[10]+0x02441453, 9); - SX_MD5STEP(F2, c, d, a, b, in[15]+0xd8a1e681, 14); - SX_MD5STEP(F2, b, c, d, a, in[ 4]+0xe7d3fbc8, 20); - SX_MD5STEP(F2, a, b, c, d, in[ 9]+0x21e1cde6, 5); - SX_MD5STEP(F2, d, a, b, c, in[14]+0xc33707d6, 9); - SX_MD5STEP(F2, c, d, a, b, in[ 3]+0xf4d50d87, 14); - SX_MD5STEP(F2, b, c, d, a, in[ 8]+0x455a14ed, 20); - SX_MD5STEP(F2, a, b, c, d, in[13]+0xa9e3e905, 5); - SX_MD5STEP(F2, d, a, b, c, in[ 2]+0xfcefa3f8, 9); - SX_MD5STEP(F2, c, d, a, b, in[ 7]+0x676f02d9, 14); - SX_MD5STEP(F2, b, c, d, a, in[12]+0x8d2a4c8a, 20); - - SX_MD5STEP(F3, a, b, c, d, in[ 5]+0xfffa3942, 4); - SX_MD5STEP(F3, d, a, b, c, in[ 8]+0x8771f681, 11); - SX_MD5STEP(F3, c, d, a, b, in[11]+0x6d9d6122, 16); - SX_MD5STEP(F3, b, c, d, a, in[14]+0xfde5380c, 23); - SX_MD5STEP(F3, a, b, c, d, in[ 1]+0xa4beea44, 4); - SX_MD5STEP(F3, d, a, b, c, in[ 4]+0x4bdecfa9, 11); - SX_MD5STEP(F3, c, d, a, b, in[ 7]+0xf6bb4b60, 16); - SX_MD5STEP(F3, b, c, d, a, in[10]+0xbebfbc70, 23); - SX_MD5STEP(F3, a, b, c, d, in[13]+0x289b7ec6, 4); - SX_MD5STEP(F3, d, a, b, c, in[ 0]+0xeaa127fa, 11); - SX_MD5STEP(F3, c, d, a, b, in[ 3]+0xd4ef3085, 16); - SX_MD5STEP(F3, b, c, d, a, in[ 6]+0x04881d05, 23); - SX_MD5STEP(F3, a, b, c, d, in[ 9]+0xd9d4d039, 4); - SX_MD5STEP(F3, d, a, b, c, in[12]+0xe6db99e5, 11); - SX_MD5STEP(F3, c, d, a, b, in[15]+0x1fa27cf8, 16); - SX_MD5STEP(F3, b, c, d, a, in[ 2]+0xc4ac5665, 23); - - SX_MD5STEP(F4, a, b, c, d, in[ 0]+0xf4292244, 6); - SX_MD5STEP(F4, d, a, b, c, in[ 7]+0x432aff97, 10); - SX_MD5STEP(F4, c, d, a, b, in[14]+0xab9423a7, 15); - SX_MD5STEP(F4, b, c, d, a, in[ 5]+0xfc93a039, 21); - SX_MD5STEP(F4, a, b, c, d, in[12]+0x655b59c3, 6); - SX_MD5STEP(F4, d, a, b, c, in[ 3]+0x8f0ccc92, 10); - SX_MD5STEP(F4, c, d, a, b, in[10]+0xffeff47d, 15); - SX_MD5STEP(F4, b, c, d, a, in[ 1]+0x85845dd1, 21); - SX_MD5STEP(F4, a, b, c, d, in[ 8]+0x6fa87e4f, 6); - SX_MD5STEP(F4, d, a, b, c, in[15]+0xfe2ce6e0, 10); - SX_MD5STEP(F4, c, d, a, b, in[ 6]+0xa3014314, 15); - SX_MD5STEP(F4, b, c, d, a, in[13]+0x4e0811a1, 21); - SX_MD5STEP(F4, a, b, c, d, in[ 4]+0xf7537e82, 6); - SX_MD5STEP(F4, d, a, b, c, in[11]+0xbd3af235, 10); - SX_MD5STEP(F4, c, d, a, b, in[ 2]+0x2ad7d2bb, 15); - SX_MD5STEP(F4, b, c, d, a, in[ 9]+0xeb86d391, 21); - - buf[0] += a; - buf[1] += b; - buf[2] += c; - buf[3] += d; -} -/* - * Update context to reflect the concatenation of another buffer full - * of bytes. - */ -JX9_PRIVATE void MD5Update(MD5Context *ctx, const unsigned char *buf, unsigned int len) -{ - sxu32 t; - - /* Update bitcount */ - t = ctx->bits[0]; - if ((ctx->bits[0] = t + ((sxu32)len << 3)) < t) - ctx->bits[1]++; /* Carry from low to high */ - ctx->bits[1] += len >> 29; - t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */ - /* Handle any leading odd-sized chunks */ - if ( t ) { - unsigned char *p = (unsigned char *)ctx->in + t; - - t = 64-t; - if (len < t) { - SyMemcpy(buf, p, len); - return; - } - SyMemcpy(buf, p, t); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (sxu32*)ctx->in); - buf += t; - len -= t; - } - /* Process data in 64-byte chunks */ - while (len >= 64) { - SyMemcpy(buf, ctx->in, 64); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (sxu32*)ctx->in); - buf += 64; - len -= 64; - } - /* Handle any remaining bytes of data.*/ - SyMemcpy(buf, ctx->in, len); -} -/* - * Final wrapup - pad to 64-byte boundary with the bit pattern - * 1 0* (64-bit count of bits processed, MSB-first) - */ -JX9_PRIVATE void MD5Final(unsigned char digest[16], MD5Context *ctx){ - unsigned count; - unsigned char *p; - - /* Compute number of bytes mod 64 */ - count = (ctx->bits[0] >> 3) & 0x3F; - - /* Set the first char of padding to 0x80.This is safe since there is - always at least one byte free */ - p = ctx->in + count; - *p++ = 0x80; - - /* Bytes of padding needed to make 64 bytes */ - count = 64 - 1 - count; - - /* Pad out to 56 mod 64 */ - if (count < 8) { - /* Two lots of padding: Pad the first block to 64 bytes */ - SyZero(p, count); - byteReverse(ctx->in, 16); - MD5Transform(ctx->buf, (sxu32*)ctx->in); - - /* Now fill the next block with 56 bytes */ - SyZero(ctx->in, 56); - } else { - /* Pad block to 56 bytes */ - SyZero(p, count-8); - } - byteReverse(ctx->in, 14); - - /* Append length in bits and transform */ - ((sxu32*)ctx->in)[ 14 ] = ctx->bits[0]; - ((sxu32*)ctx->in)[ 15 ] = ctx->bits[1]; - - MD5Transform(ctx->buf, (sxu32*)ctx->in); - byteReverse((unsigned char *)ctx->buf, 4); - SyMemcpy(ctx->buf, digest, 0x10); - SyZero(ctx, sizeof(ctx)); /* In case it's sensitive */ -} -#undef F1 -#undef F2 -#undef F3 -#undef F4 -JX9_PRIVATE sxi32 MD5Init(MD5Context *pCtx) -{ - pCtx->buf[0] = 0x67452301; - pCtx->buf[1] = 0xefcdab89; - pCtx->buf[2] = 0x98badcfe; - pCtx->buf[3] = 0x10325476; - pCtx->bits[0] = 0; - pCtx->bits[1] = 0; - - return SXRET_OK; -} -JX9_PRIVATE sxi32 SyMD5Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[16]) -{ - MD5Context sCtx; - MD5Init(&sCtx); - MD5Update(&sCtx, (const unsigned char *)pIn, nLen); - MD5Final(zDigest, &sCtx); - return SXRET_OK; -} -/* - * SHA-1 in C - * By Steve Reid - * Status: Public Domain - */ -/* - * blk0() and blk() perform the initial expand. - * I got the idea of expanding during the round function from SSLeay - * - * blk0le() for little-endian and blk0be() for big-endian. - */ -#if __GNUC__ && (defined(__i386__) || defined(__x86_64__)) -/* - * GCC by itself only generates left rotates. Use right rotates if - * possible to be kinder to dinky implementations with iterative rotate - * instructions. - */ -#define SHA_ROT(op, x, k) \ - ({ unsigned int y; asm(op " %1, %0" : "=r" (y) : "I" (k), "0" (x)); y; }) -#define rol(x, k) SHA_ROT("roll", x, k) -#define ror(x, k) SHA_ROT("rorl", x, k) - -#else -/* Generic C equivalent */ -#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) -#endif - -#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. - */ -#define a qq[0] -#define b qq[1] -#define c qq[2] -#define d qq[3] -#define e qq[4] - -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]; - SyMemcpy(buffer, (void *)block, 64); - SyMemcpy(state, qq, 5*sizeof(unsigned int)); - - /* Copy context->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 -/* - * SHA1Init - Initialize new context - */ -JX9_PRIVATE void SHA1Init(SHA1Context *context){ - /* SHA1 initialization constants */ - context->state[0] = 0x67452301; - context->state[1] = 0xEFCDAB89; - context->state[2] = 0x98BADCFE; - context->state[3] = 0x10325476; - context->state[4] = 0xC3D2E1F0; - context->count[0] = context->count[1] = 0; -} -/* - * Run your data through this. - */ -JX9_PRIVATE void SHA1Update(SHA1Context *context, const unsigned char *data, unsigned int len){ - unsigned int i, j; - - j = context->count[0]; - if ((context->count[0] += len << 3) < j) - context->count[1] += (len>>29)+1; - j = (j >> 3) & 63; - if ((j + len) > 63) { - (void)SyMemcpy(data, &context->buffer[j], (i = 64-j)); - SHA1Transform(context->state, context->buffer); - for ( ; i + 63 < len; i += 64) - SHA1Transform(context->state, &data[i]); - j = 0; - } else { - i = 0; - } - (void)SyMemcpy(&data[i], &context->buffer[j], len - i); -} -/* - * Add padding and return the message digest. - */ -JX9_PRIVATE void SHA1Final(SHA1Context *context, unsigned char digest[20]){ - unsigned int i; - unsigned char finalcount[8]; - - for (i = 0; i < 8; i++) { - finalcount[i] = (unsigned char)((context->count[(i >= 4 ? 0 : 1)] - >> ((3-(i & 3)) * 8) ) & 255); /* Endian independent */ - } - SHA1Update(context, (const unsigned char *)"\200", 1); - while ((context->count[0] & 504) != 448) - SHA1Update(context, (const unsigned char *)"\0", 1); - SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ - - if (digest) { - for (i = 0; i < 20; i++) - digest[i] = (unsigned char) - ((context->state[i>>2] >> ((3-(i & 3)) * 8) ) & 255); - } -} -#undef Rl0 -#undef Rb0 -#undef R1 -#undef R2 -#undef R3 -#undef R4 - -JX9_PRIVATE sxi32 SySha1Compute(const void *pIn, sxu32 nLen, unsigned char zDigest[20]) -{ - SHA1Context sCtx; - SHA1Init(&sCtx); - SHA1Update(&sCtx, (const unsigned char *)pIn, nLen); - SHA1Final(&sCtx, zDigest); - return SXRET_OK; -} -static const sxu32 crc32_table[] = { - 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, - 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, - 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, - 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, - 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, - 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, - 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, - 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, - 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, - 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, - 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, - 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, - 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, - 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, - 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, - 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, - 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, - 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, - 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, - 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, - 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, - 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, - 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, - 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, - 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, - 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, - 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, - 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, - 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, - 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, - 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, - 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, - 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, - 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, - 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, - 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, - 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, - 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, - 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, - 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, - 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, - 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, - 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, - 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, - 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, - 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, - 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, - 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, - 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, - 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, - 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, - 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, - 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, - 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, - 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, - 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, - 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, - 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, - 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, - 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, - 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, - 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, - 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, - 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d, -}; -#define CRC32C(c, d) (c = ( crc32_table[(c ^ (d)) & 0xFF] ^ (c>>8) ) ) -static sxu32 SyCrc32Update(sxu32 crc32, const void *pSrc, sxu32 nLen) -{ - register unsigned char *zIn = (unsigned char *)pSrc; - unsigned char *zEnd; - if( zIn == 0 ){ - return crc32; - } - zEnd = &zIn[nLen]; - for(;;){ - if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++; - if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++; - if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++; - if(zIn >= zEnd ){ break; } CRC32C(crc32, zIn[0]); zIn++; - } - - return crc32; -} -JX9_PRIVATE sxu32 SyCrc32(const void *pSrc, sxu32 nLen) -{ - return SyCrc32Update(SXU32_HIGH, pSrc, nLen); -} -#endif /* JX9_DISABLE_HASH_FUNC */ -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -#ifndef JX9_DISABLE_BUILTIN_FUNC -JX9_PRIVATE sxi32 SyBinToHexConsumer(const void *pIn, sxu32 nLen, ProcConsumer xConsumer, void *pConsumerData) -{ - static const unsigned char zHexTab[] = "0123456789abcdef"; - const unsigned char *zIn, *zEnd; - unsigned char zOut[3]; - sxi32 rc; -#if defined(UNTRUST) - if( pIn == 0 || xConsumer == 0 ){ - return SXERR_EMPTY; - } -#endif - zIn = (const unsigned char *)pIn; - zEnd = &zIn[nLen]; - for(;;){ - if( zIn >= zEnd ){ - break; - } - zOut[0] = zHexTab[zIn[0] >> 4]; zOut[1] = zHexTab[zIn[0] & 0x0F]; - rc = xConsumer((const void *)zOut, sizeof(char)*2, pConsumerData); - if( rc != SXRET_OK ){ - return rc; - } - zIn++; - } - return SXRET_OK; -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -JX9_PRIVATE void SyBigEndianPack32(unsigned char *buf,sxu32 nb) -{ - buf[3] = nb & 0xFF ; nb >>=8; - buf[2] = nb & 0xFF ; nb >>=8; - buf[1] = nb & 0xFF ; nb >>=8; - buf[0] = (unsigned char)nb ; -} -JX9_PRIVATE void SyBigEndianUnpack32(const unsigned char *buf,sxu32 *uNB) -{ - *uNB = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24); -} -JX9_PRIVATE void SyBigEndianPack16(unsigned char *buf,sxu16 nb) -{ - buf[1] = nb & 0xFF ; nb >>=8; - buf[0] = (unsigned char)nb ; -} -JX9_PRIVATE void SyBigEndianUnpack16(const unsigned char *buf,sxu16 *uNB) -{ - *uNB = buf[1] + (buf[0] << 8); -} -JX9_PRIVATE void SyBigEndianPack64(unsigned char *buf,sxu64 n64) -{ - buf[7] = n64 & 0xFF; n64 >>=8; - buf[6] = n64 & 0xFF; n64 >>=8; - buf[5] = n64 & 0xFF; n64 >>=8; - buf[4] = n64 & 0xFF; n64 >>=8; - buf[3] = n64 & 0xFF; n64 >>=8; - buf[2] = n64 & 0xFF; n64 >>=8; - buf[1] = n64 & 0xFF; n64 >>=8; - buf[0] = (sxu8)n64 ; -} -JX9_PRIVATE void SyBigEndianUnpack64(const unsigned char *buf,sxu64 *n64) -{ - sxu32 u1,u2; - u1 = buf[7] + (buf[6] << 8) + (buf[5] << 16) + (buf[4] << 24); - u2 = buf[3] + (buf[2] << 8) + (buf[1] << 16) + (buf[0] << 24); - *n64 = (((sxu64)u2) << 32) | u1; -} -JX9_PRIVATE sxi32 SyBlobAppendBig64(SyBlob *pBlob,sxu64 n64) -{ - unsigned char zBuf[8]; - sxi32 rc; - SyBigEndianPack64(zBuf,n64); - rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf)); - return rc; -} -JX9_PRIVATE sxi32 SyBlobAppendBig32(SyBlob *pBlob,sxu32 n32) -{ - unsigned char zBuf[4]; - sxi32 rc; - SyBigEndianPack32(zBuf,n32); - rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf)); - return rc; -} -JX9_PRIVATE sxi32 SyBlobAppendBig16(SyBlob *pBlob,sxu16 n16) -{ - unsigned char zBuf[2]; - sxi32 rc; - SyBigEndianPack16(zBuf,n16); - rc = SyBlobAppend(pBlob,(const void *)zBuf,sizeof(zBuf)); - return rc; -} -JX9_PRIVATE void SyTimeFormatToDos(Sytm *pFmt,sxu32 *pOut) -{ - sxi32 nDate,nTime; - nDate = ((pFmt->tm_year - 1980) << 9) + (pFmt->tm_mon << 5) + pFmt->tm_mday; - nTime = (pFmt->tm_hour << 11) + (pFmt->tm_min << 5)+ (pFmt->tm_sec >> 1); - *pOut = (nDate << 16) | nTime; -} -JX9_PRIVATE void SyDosTimeFormat(sxu32 nDosDate, Sytm *pOut) -{ - sxu16 nDate; - sxu16 nTime; - nDate = nDosDate >> 16; - nTime = nDosDate & 0xFFFF; - pOut->tm_isdst = 0; - pOut->tm_year = 1980 + (nDate >> 9); - pOut->tm_mon = (nDate % (1<<9))>>5; - pOut->tm_mday = (nDate % (1<<9))&0x1F; - pOut->tm_hour = nTime >> 11; - pOut->tm_min = (nTime % (1<<11)) >> 5; - pOut->tm_sec = ((nTime % (1<<11))& 0x1F )<<1; -} -/* - * ---------------------------------------------------------- - * File: jx9_memobj.c - * MD5: 8692d7f4cb297c0946066b4a9034c637 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: memobj.c v2.7 FreeBSD 2012-08-09 03:40 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* This file manage low-level stuff related to indexed memory objects [i.e: jx9_value] */ -/* - * Notes on memory objects [i.e: jx9_value]. - * Internally, the JX9 virtual machine manipulates nearly all JX9 values - * [i.e: string, int, float, resource, object, bool, null..] as jx9_values structures. - * Each jx9_values struct may cache multiple representations (string, - * integer etc.) of the same value. - */ -/* - * Convert a 64-bit IEEE double into a 64-bit signed integer. - * If the double is too large, return 0x8000000000000000. - * - * Most systems appear to do this simply by assigning ariables and without - * the extra range tests. - * But there are reports that windows throws an expection if the floating - * point value is out of range. - */ -static sxi64 MemObjRealToInt(jx9_value *pObj) -{ -#ifdef JX9_OMIT_FLOATING_POINT - /* Real and 64bit integer are the same when floating point arithmetic - * is omitted from the build. - */ - return pObj->x.rVal; -#else - /* - ** Many compilers we encounter do not define constants for the - ** minimum and maximum 64-bit integers, or they define them - ** inconsistently. And many do not understand the "LL" notation. - ** So we define our own static constants here using nothing - ** larger than a 32-bit integer constant. - */ - static const sxi64 maxInt = LARGEST_INT64; - static const sxi64 minInt = SMALLEST_INT64; - jx9_real r = pObj->x.rVal; - if( r<(jx9_real)minInt ){ - return minInt; - }else if( r>(jx9_real)maxInt ){ - /* minInt is correct here - not maxInt. It turns out that assigning - ** a very large positive number to an integer results in a very large - ** negative integer. This makes no sense, but it is what x86 hardware - ** does so for compatibility we will do the same in software. */ - return minInt; - }else{ - return (sxi64)r; - } -#endif -} -/* - * Convert a raw token value typically a stream of digit [i.e: hex, octal, binary or decimal] - * to a 64-bit integer. - */ -JX9_PRIVATE sxi64 jx9TokenValueToInt64(SyString *pVal) -{ - sxi64 iVal = 0; - if( pVal->nByte <= 0 ){ - return 0; - } - if( pVal->zString[0] == '0' ){ - sxi32 c; - if( pVal->nByte == sizeof(char) ){ - return 0; - } - c = pVal->zString[1]; - if( c == 'x' || c == 'X' ){ - /* Hex digit stream */ - SyHexStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0); - }else if( c == 'b' || c == 'B' ){ - /* Binary digit stream */ - SyBinaryStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0); - }else{ - /* Octal digit stream */ - SyOctalStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0); - } - }else{ - /* Decimal digit stream */ - SyStrToInt64(pVal->zString, pVal->nByte, (void *)&iVal, 0); - } - return iVal; -} -/* - * Return some kind of 64-bit integer value which is the best we can - * do at representing the value that pObj describes as a string - * representation. - */ -static sxi64 MemObjStringToInt(jx9_value *pObj) -{ - SyString sVal; - SyStringInitFromBuf(&sVal, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - return jx9TokenValueToInt64(&sVal); -} -/* - * Return some kind of integer value which is the best we can - * do at representing the value that pObj describes as an integer. - * If pObj is an integer, then the value is exact. If pObj is - * a floating-point then the value returned is the integer part. - * If pObj is a string, then we make an attempt to convert it into - * a integer and return that. - * If pObj represents a NULL value, return 0. - */ -static sxi64 MemObjIntValue(jx9_value *pObj) -{ - sxi32 iFlags; - iFlags = pObj->iFlags; - if (iFlags & MEMOBJ_REAL ){ - return MemObjRealToInt(&(*pObj)); - }else if( iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){ - return pObj->x.iVal; - }else if (iFlags & MEMOBJ_STRING) { - return MemObjStringToInt(&(*pObj)); - }else if( iFlags & MEMOBJ_NULL ){ - return 0; - }else if( iFlags & MEMOBJ_HASHMAP ){ - jx9_hashmap *pMap = (jx9_hashmap *)pObj->x.pOther; - sxu32 n = pMap->nEntry; - jx9HashmapUnref(pMap); - /* Return total number of entries in the hashmap */ - return n; - }else if(iFlags & MEMOBJ_RES ){ - return pObj->x.pOther != 0; - } - /* CANT HAPPEN */ - return 0; -} -/* - * Return some kind of real value which is the best we can - * do at representing the value that pObj describes as a real. - * If pObj is a real, then the value is exact.If pObj is an - * integer then the integer is promoted to real and that value - * is returned. - * If pObj is a string, then we make an attempt to convert it - * into a real and return that. - * If pObj represents a NULL value, return 0.0 - */ -static jx9_real MemObjRealValue(jx9_value *pObj) -{ - sxi32 iFlags; - iFlags = pObj->iFlags; - if( iFlags & MEMOBJ_REAL ){ - return pObj->x.rVal; - }else if (iFlags & (MEMOBJ_INT|MEMOBJ_BOOL) ){ - return (jx9_real)pObj->x.iVal; - }else if (iFlags & MEMOBJ_STRING){ - SyString sString; -#ifdef JX9_OMIT_FLOATING_POINT - jx9_real rVal = 0; -#else - jx9_real rVal = 0.0; -#endif - SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - if( SyBlobLength(&pObj->sBlob) > 0 ){ - /* Convert as much as we can */ -#ifdef JX9_OMIT_FLOATING_POINT - rVal = MemObjStringToInt(&(*pObj)); -#else - SyStrToReal(sString.zString, sString.nByte, (void *)&rVal, 0); -#endif - } - return rVal; - }else if( iFlags & MEMOBJ_NULL ){ -#ifdef JX9_OMIT_FLOATING_POINT - return 0; -#else - return 0.0; -#endif - }else if( iFlags & MEMOBJ_HASHMAP ){ - /* Return the total number of entries in the hashmap */ - jx9_hashmap *pMap = (jx9_hashmap *)pObj->x.pOther; - jx9_real n = (jx9_real)pMap->nEntry; - jx9HashmapUnref(pMap); - return n; - }else if(iFlags & MEMOBJ_RES ){ - return (jx9_real)(pObj->x.pOther != 0); - } - /* NOT REACHED */ - return 0; -} -/* - * Return the string representation of a given jx9_value. - * This function never fail and always return SXRET_OK. - */ -static sxi32 MemObjStringValue(SyBlob *pOut,jx9_value *pObj) -{ - if( pObj->iFlags & MEMOBJ_REAL ){ - SyBlobFormat(&(*pOut), "%.15g", pObj->x.rVal); - }else if( pObj->iFlags & MEMOBJ_INT ){ - SyBlobFormat(&(*pOut), "%qd", pObj->x.iVal); - /* %qd (BSD quad) is equivalent to %lld in the libc printf */ - }else if( pObj->iFlags & MEMOBJ_BOOL ){ - if( pObj->x.iVal ){ - SyBlobAppend(&(*pOut),"true", sizeof("true")-1); - }else{ - SyBlobAppend(&(*pOut),"false", sizeof("false")-1); - } - }else if( pObj->iFlags & MEMOBJ_HASHMAP ){ - /* Serialize JSON object or array */ - jx9JsonSerialize(pObj,pOut); - jx9HashmapUnref((jx9_hashmap *)pObj->x.pOther); - }else if(pObj->iFlags & MEMOBJ_RES ){ - SyBlobFormat(&(*pOut), "ResourceID_%#x", pObj->x.pOther); - } - return SXRET_OK; -} -/* - * Return some kind of boolean value which is the best we can do - * at representing the value that pObj describes as a boolean. - * When converting to boolean, the following values are considered FALSE: - * NULL - * the boolean FALSE itself. - * the integer 0 (zero). - * the real 0.0 (zero). - * the empty string, a stream of zero [i.e: "0", "00", "000", ...] and the string - * "false". - * an array with zero elements. - */ -static sxi32 MemObjBooleanValue(jx9_value *pObj) -{ - sxi32 iFlags; - iFlags = pObj->iFlags; - if (iFlags & MEMOBJ_REAL ){ -#ifdef JX9_OMIT_FLOATING_POINT - return pObj->x.rVal ? 1 : 0; -#else - return pObj->x.rVal != 0.0 ? 1 : 0; -#endif - }else if( iFlags & MEMOBJ_INT ){ - return pObj->x.iVal ? 1 : 0; - }else if (iFlags & MEMOBJ_STRING) { - SyString sString; - SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - if( sString.nByte == 0 ){ - /* Empty string */ - return 0; - }else if( (sString.nByte == sizeof("true") - 1 && SyStrnicmp(sString.zString, "true", sizeof("true")-1) == 0) || - (sString.nByte == sizeof("on") - 1 && SyStrnicmp(sString.zString, "on", sizeof("on")-1) == 0) || - (sString.nByte == sizeof("yes") - 1 && SyStrnicmp(sString.zString, "yes", sizeof("yes")-1) == 0) ){ - return 1; - }else if( sString.nByte == sizeof("false") - 1 && SyStrnicmp(sString.zString, "false", sizeof("false")-1) == 0 ){ - return 0; - }else{ - const char *zIn, *zEnd; - zIn = sString.zString; - zEnd = &zIn[sString.nByte]; - while( zIn < zEnd && zIn[0] == '0' ){ - zIn++; - } - return zIn >= zEnd ? 0 : 1; - } - }else if( iFlags & MEMOBJ_NULL ){ - return 0; - }else if( iFlags & MEMOBJ_HASHMAP ){ - jx9_hashmap *pMap = (jx9_hashmap *)pObj->x.pOther; - sxu32 n = pMap->nEntry; - jx9HashmapUnref(pMap); - return n > 0 ? TRUE : FALSE; - }else if(iFlags & MEMOBJ_RES ){ - return pObj->x.pOther != 0; - } - /* NOT REACHED */ - return 0; -} -/* - * If the jx9_value is of type real, try to make it an integer also. - */ -static sxi32 MemObjTryIntger(jx9_value *pObj) -{ - sxi64 iVal = MemObjRealToInt(&(*pObj)); - /* Only mark the value as an integer if - ** - ** (1) the round-trip conversion real->int->real is a no-op, and - ** (2) The integer is neither the largest nor the smallest - ** possible integer - ** - ** The second and third terms in the following conditional enforces - ** the second condition under the assumption that addition overflow causes - ** values to wrap around. On x86 hardware, the third term is always - ** true and could be omitted. But we leave it in because other - ** architectures might behave differently. - */ - if( pObj->x.rVal ==(jx9_real)iVal && iVal>SMALLEST_INT64 && iValx.iVal = iVal; - pObj->iFlags = MEMOBJ_INT; - } - return SXRET_OK; -} -/* - * Convert a jx9_value to type integer.Invalidate any prior representations. - */ -JX9_PRIVATE sxi32 jx9MemObjToInteger(jx9_value *pObj) -{ - if( (pObj->iFlags & MEMOBJ_INT) == 0 ){ - /* Preform the conversion */ - pObj->x.iVal = MemObjIntValue(&(*pObj)); - /* Invalidate any prior representations */ - SyBlobRelease(&pObj->sBlob); - MemObjSetType(pObj, MEMOBJ_INT); - } - return SXRET_OK; -} -/* - * Convert a jx9_value to type real (Try to get an integer representation also). - * Invalidate any prior representations - */ -JX9_PRIVATE sxi32 jx9MemObjToReal(jx9_value *pObj) -{ - if((pObj->iFlags & MEMOBJ_REAL) == 0 ){ - /* Preform the conversion */ - pObj->x.rVal = MemObjRealValue(&(*pObj)); - /* Invalidate any prior representations */ - SyBlobRelease(&pObj->sBlob); - MemObjSetType(pObj, MEMOBJ_REAL); - } - return SXRET_OK; -} -/* - * Convert a jx9_value to type boolean.Invalidate any prior representations. - */ -JX9_PRIVATE sxi32 jx9MemObjToBool(jx9_value *pObj) -{ - if( (pObj->iFlags & MEMOBJ_BOOL) == 0 ){ - /* Preform the conversion */ - pObj->x.iVal = MemObjBooleanValue(&(*pObj)); - /* Invalidate any prior representations */ - SyBlobRelease(&pObj->sBlob); - MemObjSetType(pObj, MEMOBJ_BOOL); - } - return SXRET_OK; -} -/* - * Convert a jx9_value to type string.Prior representations are NOT invalidated. - */ -JX9_PRIVATE sxi32 jx9MemObjToString(jx9_value *pObj) -{ - sxi32 rc = SXRET_OK; - if( (pObj->iFlags & MEMOBJ_STRING) == 0 ){ - /* Perform the conversion */ - SyBlobReset(&pObj->sBlob); /* Reset the internal buffer */ - rc = MemObjStringValue(&pObj->sBlob, &(*pObj)); - MemObjSetType(pObj, MEMOBJ_STRING); - } - return rc; -} -/* - * Nullify a jx9_value.In other words invalidate any prior - * representation. - */ -JX9_PRIVATE sxi32 jx9MemObjToNull(jx9_value *pObj) -{ - return jx9MemObjRelease(pObj); -} -/* - * Convert a jx9_value to type array.Invalidate any prior representations. - * According to the JX9 language reference manual. - * For any of the types: integer, float, string, boolean converting a value - * to an array results in an array with a single element with index zero - * and the value of the scalar which was converted. - */ -JX9_PRIVATE sxi32 jx9MemObjToHashmap(jx9_value *pObj) -{ - if( (pObj->iFlags & MEMOBJ_HASHMAP) == 0 ){ - jx9_hashmap *pMap; - /* Allocate a new hashmap instance */ - pMap = jx9NewHashmap(pObj->pVm, 0, 0); - if( pMap == 0 ){ - return SXERR_MEM; - } - if( (pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_RES)) == 0 ){ - /* - * According to the JX9 language reference manual. - * For any of the types: integer, float, string, boolean converting a value - * to an array results in an array with a single element with index zero - * and the value of the scalar which was converted. - */ - /* Insert a single element */ - jx9HashmapInsert(pMap, 0/* Automatic index assign */, &(*pObj)); - SyBlobRelease(&pObj->sBlob); - } - /* Invalidate any prior representation */ - MemObjSetType(pObj, MEMOBJ_HASHMAP); - pObj->x.pOther = pMap; - } - return SXRET_OK; -} -/* - * Return a pointer to the appropriate convertion method associated - * with the given type. - * Note on type juggling. - * Accoding to the JX9 language reference manual - * JX9 does not require (or support) explicit type definition in variable - * declaration; a variable's type is determined by the context in which - * the variable is used. That is to say, if a string value is assigned - * to variable $var, $var becomes a string. If an integer value is then - * assigned to $var, it becomes an integer. - */ -JX9_PRIVATE ProcMemObjCast jx9MemObjCastMethod(sxi32 iFlags) -{ - if( iFlags & MEMOBJ_STRING ){ - return jx9MemObjToString; - }else if( iFlags & MEMOBJ_INT ){ - return jx9MemObjToInteger; - }else if( iFlags & MEMOBJ_REAL ){ - return jx9MemObjToReal; - }else if( iFlags & MEMOBJ_BOOL ){ - return jx9MemObjToBool; - }else if( iFlags & MEMOBJ_HASHMAP ){ - return jx9MemObjToHashmap; - } - /* NULL cast */ - return jx9MemObjToNull; -} -/* - * Check whether the jx9_value is numeric [i.e: int/float/bool] or looks - * like a numeric number [i.e: if the jx9_value is of type string.]. - * Return TRUE if numeric.FALSE otherwise. - */ -JX9_PRIVATE sxi32 jx9MemObjIsNumeric(jx9_value *pObj) -{ - if( pObj->iFlags & ( MEMOBJ_BOOL|MEMOBJ_INT|MEMOBJ_REAL) ){ - return TRUE; - }else if( pObj->iFlags & (MEMOBJ_NULL|MEMOBJ_HASHMAP|MEMOBJ_RES) ){ - return FALSE; - }else if( pObj->iFlags & MEMOBJ_STRING ){ - SyString sStr; - sxi32 rc; - SyStringInitFromBuf(&sStr, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - if( sStr.nByte <= 0 ){ - /* Empty string */ - return FALSE; - } - /* Check if the string representation looks like a numeric number */ - rc = SyStrIsNumeric(sStr.zString, sStr.nByte, 0, 0); - return rc == SXRET_OK ? TRUE : FALSE; - } - /* NOT REACHED */ - return FALSE; -} -/* - * Check whether the jx9_value is empty.Return TRUE if empty. - * FALSE otherwise. - * An jx9_value is considered empty if the following are true: - * NULL value. - * Boolean FALSE. - * Integer/Float with a 0 (zero) value. - * An empty string or a stream of 0 (zero) [i.e: "0", "00", "000", ...]. - * An empty array. - * NOTE - * OBJECT VALUE MUST NOT BE MODIFIED. - */ -JX9_PRIVATE sxi32 jx9MemObjIsEmpty(jx9_value *pObj) -{ - if( pObj->iFlags & MEMOBJ_NULL ){ - return TRUE; - }else if( pObj->iFlags & MEMOBJ_INT ){ - return pObj->x.iVal == 0 ? TRUE : FALSE; - }else if( pObj->iFlags & MEMOBJ_REAL ){ - return pObj->x.rVal == (jx9_real)0 ? TRUE : FALSE; - }else if( pObj->iFlags & MEMOBJ_BOOL ){ - return !pObj->x.iVal; - }else if( pObj->iFlags & MEMOBJ_STRING ){ - if( SyBlobLength(&pObj->sBlob) <= 0 ){ - return TRUE; - }else{ - const char *zIn, *zEnd; - zIn = (const char *)SyBlobData(&pObj->sBlob); - zEnd = &zIn[SyBlobLength(&pObj->sBlob)]; - while( zIn < zEnd ){ - if( zIn[0] != '0' ){ - break; - } - zIn++; - } - return zIn >= zEnd ? TRUE : FALSE; - } - }else if( pObj->iFlags & MEMOBJ_HASHMAP ){ - jx9_hashmap *pMap = (jx9_hashmap *)pObj->x.pOther; - return pMap->nEntry == 0 ? TRUE : FALSE; - }else if ( pObj->iFlags & (MEMOBJ_RES) ){ - return FALSE; - } - /* Assume empty by default */ - return TRUE; -} -/* - * Convert a jx9_value so that it has types MEMOBJ_REAL or MEMOBJ_INT - * or both. - * Invalidate any prior representations. Every effort is made to force - * the conversion, even if the input is a string that does not look - * completely like a number.Convert as much of the string as we can - * and ignore the rest. - */ -JX9_PRIVATE sxi32 jx9MemObjToNumeric(jx9_value *pObj) -{ - if( pObj->iFlags & (MEMOBJ_INT|MEMOBJ_REAL|MEMOBJ_BOOL|MEMOBJ_NULL) ){ - if( pObj->iFlags & (MEMOBJ_BOOL|MEMOBJ_NULL) ){ - if( pObj->iFlags & MEMOBJ_NULL ){ - pObj->x.iVal = 0; - } - MemObjSetType(pObj, MEMOBJ_INT); - } - /* Already numeric */ - return SXRET_OK; - } - if( pObj->iFlags & MEMOBJ_STRING ){ - sxi32 rc = SXERR_INVALID; - sxu8 bReal = FALSE; - SyString sString; - SyStringInitFromBuf(&sString, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - /* Check if the given string looks like a numeric number */ - if( sString.nByte > 0 ){ - rc = SyStrIsNumeric(sString.zString, sString.nByte, &bReal, 0); - } - if( bReal ){ - jx9MemObjToReal(&(*pObj)); - }else{ - if( rc != SXRET_OK ){ - /* The input does not look at all like a number, set the value to 0 */ - pObj->x.iVal = 0; - }else{ - /* Convert as much as we can */ - pObj->x.iVal = MemObjStringToInt(&(*pObj)); - } - MemObjSetType(pObj, MEMOBJ_INT); - SyBlobRelease(&pObj->sBlob); - } - }else if(pObj->iFlags & (MEMOBJ_HASHMAP|MEMOBJ_RES)){ - jx9MemObjToInteger(pObj); - }else{ - /* Perform a blind cast */ - jx9MemObjToReal(&(*pObj)); - } - return SXRET_OK; -} -/* - * Try a get an integer representation of the given jx9_value. - * If the jx9_value is not of type real, this function is a no-op. - */ -JX9_PRIVATE sxi32 jx9MemObjTryInteger(jx9_value *pObj) -{ - if( pObj->iFlags & MEMOBJ_REAL ){ - /* Work only with reals */ - MemObjTryIntger(&(*pObj)); - } - return SXRET_OK; -} -/* - * Initialize a jx9_value to the null type. - */ -JX9_PRIVATE sxi32 jx9MemObjInit(jx9_vm *pVm, jx9_value *pObj) -{ - /* Zero the structure */ - SyZero(pObj, sizeof(jx9_value)); - /* Initialize fields */ - pObj->pVm = pVm; - SyBlobInit(&pObj->sBlob, &pVm->sAllocator); - /* Set the NULL type */ - pObj->iFlags = MEMOBJ_NULL; - return SXRET_OK; -} -/* - * Initialize a jx9_value to the integer type. - */ -JX9_PRIVATE sxi32 jx9MemObjInitFromInt(jx9_vm *pVm, jx9_value *pObj, sxi64 iVal) -{ - /* Zero the structure */ - SyZero(pObj, sizeof(jx9_value)); - /* Initialize fields */ - pObj->pVm = pVm; - SyBlobInit(&pObj->sBlob, &pVm->sAllocator); - /* Set the desired type */ - pObj->x.iVal = iVal; - pObj->iFlags = MEMOBJ_INT; - return SXRET_OK; -} -/* - * Initialize a jx9_value to the boolean type. - */ -JX9_PRIVATE sxi32 jx9MemObjInitFromBool(jx9_vm *pVm, jx9_value *pObj, sxi32 iVal) -{ - /* Zero the structure */ - SyZero(pObj, sizeof(jx9_value)); - /* Initialize fields */ - pObj->pVm = pVm; - SyBlobInit(&pObj->sBlob, &pVm->sAllocator); - /* Set the desired type */ - pObj->x.iVal = iVal ? 1 : 0; - pObj->iFlags = MEMOBJ_BOOL; - return SXRET_OK; -} -#if 0 -/* - * Initialize a jx9_value to the real type. - */ -JX9_PRIVATE sxi32 jx9MemObjInitFromReal(jx9_vm *pVm, jx9_value *pObj, jx9_real rVal) -{ - /* Zero the structure */ - SyZero(pObj, sizeof(jx9_value)); - /* Initialize fields */ - pObj->pVm = pVm; - SyBlobInit(&pObj->sBlob, &pVm->sAllocator); - /* Set the desired type */ - pObj->x.rVal = rVal; - pObj->iFlags = MEMOBJ_REAL; - return SXRET_OK; -} -#endif -/* - * Initialize a jx9_value to the array type. - */ -JX9_PRIVATE sxi32 jx9MemObjInitFromArray(jx9_vm *pVm, jx9_value *pObj, jx9_hashmap *pArray) -{ - /* Zero the structure */ - SyZero(pObj, sizeof(jx9_value)); - /* Initialize fields */ - pObj->pVm = pVm; - SyBlobInit(&pObj->sBlob, &pVm->sAllocator); - /* Set the desired type */ - pObj->iFlags = MEMOBJ_HASHMAP; - pObj->x.pOther = pArray; - return SXRET_OK; -} -/* - * Initialize a jx9_value to the string type. - */ -JX9_PRIVATE sxi32 jx9MemObjInitFromString(jx9_vm *pVm, jx9_value *pObj, const SyString *pVal) -{ - /* Zero the structure */ - SyZero(pObj, sizeof(jx9_value)); - /* Initialize fields */ - pObj->pVm = pVm; - SyBlobInit(&pObj->sBlob, &pVm->sAllocator); - if( pVal ){ - /* Append contents */ - SyBlobAppend(&pObj->sBlob, (const void *)pVal->zString, pVal->nByte); - } - /* Set the desired type */ - pObj->iFlags = MEMOBJ_STRING; - return SXRET_OK; -} -/* - * Append some contents to the internal buffer of a given jx9_value. - * If the given jx9_value is not of type string, this function - * invalidate any prior representation and set the string type. - * Then a simple append operation is performed. - */ -JX9_PRIVATE sxi32 jx9MemObjStringAppend(jx9_value *pObj, const char *zData, sxu32 nLen) -{ - sxi32 rc; - if( (pObj->iFlags & MEMOBJ_STRING) == 0 ){ - /* Invalidate any prior representation */ - jx9MemObjRelease(pObj); - MemObjSetType(pObj, MEMOBJ_STRING); - } - /* Append contents */ - rc = SyBlobAppend(&pObj->sBlob, zData, nLen); - return rc; -} -#if 0 -/* - * Format and append some contents to the internal buffer of a given jx9_value. - * If the given jx9_value is not of type string, this function invalidate - * any prior representation and set the string type. - * Then a simple format and append operation is performed. - */ -JX9_PRIVATE sxi32 jx9MemObjStringFormat(jx9_value *pObj, const char *zFormat, va_list ap) -{ - sxi32 rc; - if( (pObj->iFlags & MEMOBJ_STRING) == 0 ){ - /* Invalidate any prior representation */ - jx9MemObjRelease(pObj); - MemObjSetType(pObj, MEMOBJ_STRING); - } - /* Format and append contents */ - rc = SyBlobFormatAp(&pObj->sBlob, zFormat, ap); - return rc; -} -#endif -/* - * Duplicate the contents of a jx9_value. - */ -JX9_PRIVATE sxi32 jx9MemObjStore(jx9_value *pSrc, jx9_value *pDest) -{ - jx9_hashmap *pMap = 0; - sxi32 rc; - if( pSrc->iFlags & MEMOBJ_HASHMAP ){ - /* Increment reference count */ - ((jx9_hashmap *)pSrc->x.pOther)->iRef++; - } - if( pDest->iFlags & MEMOBJ_HASHMAP ){ - pMap = (jx9_hashmap *)pDest->x.pOther; - } - SyMemcpy((const void *)&(*pSrc), &(*pDest), sizeof(jx9_value)-(sizeof(jx9_vm *)+sizeof(SyBlob)+sizeof(sxu32))); - rc = SXRET_OK; - if( SyBlobLength(&pSrc->sBlob) > 0 ){ - SyBlobReset(&pDest->sBlob); - rc = SyBlobDup(&pSrc->sBlob, &pDest->sBlob); - }else{ - if( SyBlobLength(&pDest->sBlob) > 0 ){ - SyBlobRelease(&pDest->sBlob); - } - } - if( pMap ){ - jx9HashmapUnref(pMap); - } - return rc; -} -/* - * Duplicate the contents of a jx9_value but do not copy internal - * buffer contents, simply point to it. - */ -JX9_PRIVATE sxi32 jx9MemObjLoad(jx9_value *pSrc, jx9_value *pDest) -{ - SyMemcpy((const void *)&(*pSrc), &(*pDest), - sizeof(jx9_value)-(sizeof(jx9_vm *)+sizeof(SyBlob)+sizeof(sxu32))); - if( pSrc->iFlags & MEMOBJ_HASHMAP ){ - /* Increment reference count */ - ((jx9_hashmap *)pSrc->x.pOther)->iRef++; - } - if( SyBlobLength(&pDest->sBlob) > 0 ){ - SyBlobRelease(&pDest->sBlob); - } - if( SyBlobLength(&pSrc->sBlob) > 0 ){ - SyBlobReadOnly(&pDest->sBlob, SyBlobData(&pSrc->sBlob), SyBlobLength(&pSrc->sBlob)); - } - return SXRET_OK; -} -/* - * Invalidate any prior representation of a given jx9_value. - */ -JX9_PRIVATE sxi32 jx9MemObjRelease(jx9_value *pObj) -{ - if( (pObj->iFlags & MEMOBJ_NULL) == 0 ){ - if( pObj->iFlags & MEMOBJ_HASHMAP ){ - jx9HashmapUnref((jx9_hashmap *)pObj->x.pOther); - } - /* Release the internal buffer */ - SyBlobRelease(&pObj->sBlob); - /* Invalidate any prior representation */ - pObj->iFlags = MEMOBJ_NULL; - } - return SXRET_OK; -} -/* - * Compare two jx9_values. - * Return 0 if the values are equals, > 0 if pObj1 is greater than pObj2 - * or < 0 if pObj2 is greater than pObj1. - * Type comparison table taken from the JX9 language reference manual. - * Comparisons of $x with JX9 functions Expression - * gettype() empty() is_null() isset() boolean : if($x) - * $x = ""; string TRUE FALSE TRUE FALSE - * $x = null NULL TRUE TRUE FALSE FALSE - * var $x; NULL TRUE TRUE FALSE FALSE - * $x is undefined NULL TRUE TRUE FALSE FALSE - * $x = array(); array TRUE FALSE TRUE FALSE - * $x = false; boolean TRUE FALSE TRUE FALSE - * $x = true; boolean FALSE FALSE TRUE TRUE - * $x = 1; integer FALSE FALSE TRUE TRUE - * $x = 42; integer FALSE FALSE TRUE TRUE - * $x = 0; integer TRUE FALSE TRUE FALSE - * $x = -1; integer FALSE FALSE TRUE TRUE - * $x = "1"; string FALSE FALSE TRUE TRUE - * $x = "0"; string TRUE FALSE TRUE FALSE - * $x = "-1"; string FALSE FALSE TRUE TRUE - * $x = "jx9"; string FALSE FALSE TRUE TRUE - * $x = "true"; string FALSE FALSE TRUE TRUE - * $x = "false"; string FALSE FALSE TRUE TRUE - * Loose comparisons with == - * TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "jx9" "" - * TRUE TRUE FALSE TRUE FALSE TRUE TRUE FALSE TRUE FALSE FALSE TRUE FALSE - * FALSE FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE TRUE FALSE TRUE - * 1 TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE - * 0 FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE TRUE FALSE TRUE TRUE - * -1 TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE - * "1" TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE - * "0" FALSE TRUE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE - * "-1" TRUE FALSE FALSE FALSE TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE - * NULL FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE TRUE FALSE TRUE - * array() FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE TRUE FALSE FALSE - * "jx9" TRUE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE - * "" FALSE TRUE FALSE TRUE FALSE FALSE FALSE FALSE TRUE FALSE FALSE TRUE - * Strict comparisons with === - * TRUE FALSE 1 0 -1 "1" "0" "-1" NULL array() "jx9" "" - * TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE - * FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE - * 1 FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE - * 0 FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE - * -1 FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE - * "1" FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE FALSE - * "0" FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE FALSE - * "-1" FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE FALSE - * NULL FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE FALSE - * array() FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE FALSE - * "jx9" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE FALSE - * "" FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE FALSE TRUE - */ -JX9_PRIVATE sxi32 jx9MemObjCmp(jx9_value *pObj1, jx9_value *pObj2, int bStrict, int iNest) -{ - sxi32 iComb; - sxi32 rc; - if( bStrict ){ - sxi32 iF1, iF2; - /* Strict comparisons with === */ - iF1 = pObj1->iFlags; - iF2 = pObj2->iFlags; - if( iF1 != iF2 ){ - /* Not of the same type */ - return 1; - } - } - /* Combine flag together */ - iComb = pObj1->iFlags|pObj2->iFlags; - if( iComb & (MEMOBJ_RES|MEMOBJ_BOOL) ){ - /* Convert to boolean: Keep in mind FALSE < TRUE */ - if( (pObj1->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pObj1); - } - if( (pObj2->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pObj2); - } - return (sxi32)((pObj1->x.iVal != 0) - (pObj2->x.iVal != 0)); - }else if( iComb & MEMOBJ_NULL ){ - if( (pObj1->iFlags & MEMOBJ_NULL) == 0 ){ - return 1; - } - if( (pObj2->iFlags & MEMOBJ_NULL) == 0 ){ - return -1; - } - }else if ( iComb & MEMOBJ_HASHMAP ){ - /* Hashmap aka 'array' comparison */ - if( (pObj1->iFlags & MEMOBJ_HASHMAP) == 0 ){ - /* Array is always greater */ - return -1; - } - if( (pObj2->iFlags & MEMOBJ_HASHMAP) == 0 ){ - /* Array is always greater */ - return 1; - } - /* Perform the comparison */ - rc = jx9HashmapCmp((jx9_hashmap *)pObj1->x.pOther, (jx9_hashmap *)pObj2->x.pOther, bStrict); - return rc; - }else if ( iComb & MEMOBJ_STRING ){ - SyString s1, s2; - /* Perform a strict string comparison.*/ - if( (pObj1->iFlags&MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(pObj1); - } - if( (pObj2->iFlags&MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(pObj2); - } - SyStringInitFromBuf(&s1, SyBlobData(&pObj1->sBlob), SyBlobLength(&pObj1->sBlob)); - SyStringInitFromBuf(&s2, SyBlobData(&pObj2->sBlob), SyBlobLength(&pObj2->sBlob)); - /* - * Strings are compared using memcmp(). If one value is an exact prefix of the - * other, then the shorter value is less than the longer value. - */ - rc = SyMemcmp((const void *)s1.zString, (const void *)s2.zString, SXMIN(s1.nByte, s2.nByte)); - if( rc == 0 ){ - if( s1.nByte != s2.nByte ){ - rc = s1.nByte < s2.nByte ? -1 : 1; - } - } - return rc; - }else if( iComb & (MEMOBJ_INT|MEMOBJ_REAL) ){ - /* Perform a numeric comparison if one of the operand is numeric(integer or real) */ - if( (pObj1->iFlags & (MEMOBJ_INT|MEMOBJ_REAL)) == 0 ){ - jx9MemObjToNumeric(pObj1); - } - if( (pObj2->iFlags & (MEMOBJ_INT|MEMOBJ_REAL)) == 0 ){ - jx9MemObjToNumeric(pObj2); - } - if( (pObj1->iFlags & pObj2->iFlags & MEMOBJ_INT) == 0) { - jx9_real r1, r2; - /* Compare as reals */ - if( (pObj1->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pObj1); - } - r1 = pObj1->x.rVal; - if( (pObj2->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pObj2); - } - r2 = pObj2->x.rVal; - if( r1 > r2 ){ - return 1; - }else if( r1 < r2 ){ - return -1; - } - return 0; - }else{ - /* Integer comparison */ - if( pObj1->x.iVal > pObj2->x.iVal ){ - return 1; - }else if( pObj1->x.iVal < pObj2->x.iVal ){ - return -1; - } - return 0; - } - } - /* NOT REACHED */ - SXUNUSED(iNest); - return 0; -} -/* - * Perform an addition operation of two jx9_values. - * The reason this function is implemented here rather than 'vm.c' - * is that the '+' operator is overloaded. - * That is, the '+' operator is used for arithmetic operation and also - * used for operation on arrays [i.e: union]. When used with an array - * The + operator returns the right-hand array appended to the left-hand array. - * For keys that exist in both arrays, the elements from the left-hand array - * will be used, and the matching elements from the right-hand array will - * be ignored. - * This function take care of handling all the scenarios. - */ -JX9_PRIVATE sxi32 jx9MemObjAdd(jx9_value *pObj1, jx9_value *pObj2, int bAddStore) -{ - if( ((pObj1->iFlags|pObj2->iFlags) & MEMOBJ_HASHMAP) == 0 ){ - /* Arithemtic operation */ - jx9MemObjToNumeric(pObj1); - jx9MemObjToNumeric(pObj2); - if( (pObj1->iFlags|pObj2->iFlags) & MEMOBJ_REAL ){ - /* Floating point arithmetic */ - jx9_real a, b; - if( (pObj1->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pObj1); - } - if( (pObj2->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pObj2); - } - a = pObj1->x.rVal; - b = pObj2->x.rVal; - pObj1->x.rVal = a+b; - MemObjSetType(pObj1, MEMOBJ_REAL); - /* Try to get an integer representation also */ - MemObjTryIntger(&(*pObj1)); - }else{ - /* Integer arithmetic */ - sxi64 a, b; - a = pObj1->x.iVal; - b = pObj2->x.iVal; - pObj1->x.iVal = a+b; - MemObjSetType(pObj1, MEMOBJ_INT); - } - }else{ - if( (pObj1->iFlags|pObj2->iFlags) & MEMOBJ_HASHMAP ){ - jx9_hashmap *pMap; - sxi32 rc; - if( bAddStore ){ - /* Do not duplicate the hashmap, use the left one since its an add&store operation. - */ - if( (pObj1->iFlags & MEMOBJ_HASHMAP) == 0 ){ - /* Force a hashmap cast */ - rc = jx9MemObjToHashmap(pObj1); - if( rc != SXRET_OK ){ - jx9VmThrowError(pObj1->pVm, 0, JX9_CTX_ERR, "JX9 is running out of memory while creating array"); - return rc; - } - } - /* Point to the structure that describe the hashmap */ - pMap = (jx9_hashmap *)pObj1->x.pOther; - }else{ - /* Create a new hashmap */ - pMap = jx9NewHashmap(pObj1->pVm, 0, 0); - if( pMap == 0){ - jx9VmThrowError(pObj1->pVm, 0, JX9_CTX_ERR, "JX9 is running out of memory while creating array"); - return SXERR_MEM; - } - } - if( !bAddStore ){ - if(pObj1->iFlags & MEMOBJ_HASHMAP ){ - /* Perform a hashmap duplication */ - jx9HashmapDup((jx9_hashmap *)pObj1->x.pOther, pMap); - }else{ - if((pObj1->iFlags & MEMOBJ_NULL) == 0 ){ - /* Simple insertion */ - jx9HashmapInsert(pMap, 0, pObj1); - } - } - } - /* Perform the union */ - if(pObj2->iFlags & MEMOBJ_HASHMAP ){ - jx9HashmapUnion(pMap, (jx9_hashmap *)pObj2->x.pOther); - }else{ - if((pObj2->iFlags & MEMOBJ_NULL) == 0 ){ - /* Simple insertion */ - jx9HashmapInsert(pMap, 0, pObj2); - } - } - /* Reflect the change */ - if( pObj1->iFlags & MEMOBJ_STRING ){ - SyBlobRelease(&pObj1->sBlob); - } - pObj1->x.pOther = pMap; - MemObjSetType(pObj1, MEMOBJ_HASHMAP); - } - } - return SXRET_OK; -} -/* - * Return a printable representation of the type of a given - * jx9_value. - */ -JX9_PRIVATE const char * jx9MemObjTypeDump(jx9_value *pVal) -{ - const char *zType = ""; - if( pVal->iFlags & MEMOBJ_NULL ){ - zType = "null"; - }else if( pVal->iFlags & MEMOBJ_INT ){ - zType = "int"; - }else if( pVal->iFlags & MEMOBJ_REAL ){ - zType = "float"; - }else if( pVal->iFlags & MEMOBJ_STRING ){ - zType = "string"; - }else if( pVal->iFlags & MEMOBJ_BOOL ){ - zType = "bool"; - }else if( pVal->iFlags & MEMOBJ_HASHMAP ){ - jx9_hashmap *pMap = (jx9_hashmap *)pVal->x.pOther; - if( pMap->iFlags & HASHMAP_JSON_OBJECT ){ - zType = "JSON Object"; - }else{ - zType = "JSON Array"; - } - }else if( pVal->iFlags & MEMOBJ_RES ){ - zType = "resource"; - } - return zType; -} -/* - * Dump a jx9_value [i.e: get a printable representation of it's type and contents.]. - * Store the dump in the given blob. - */ -JX9_PRIVATE sxi32 jx9MemObjDump( - SyBlob *pOut, /* Store the dump here */ - jx9_value *pObj /* Dump this */ - ) -{ - sxi32 rc = SXRET_OK; - const char *zType; - /* Get value type first */ - zType = jx9MemObjTypeDump(pObj); - SyBlobAppend(&(*pOut), zType, SyStrlen(zType)); - if((pObj->iFlags & MEMOBJ_NULL) == 0 ){ - SyBlobAppend(&(*pOut), "(", sizeof(char)); - if( pObj->iFlags & MEMOBJ_HASHMAP ){ - jx9_hashmap *pMap = (jx9_hashmap *)pObj->x.pOther; - SyBlobFormat(pOut,"%u ",pMap->nEntry); - /* Dump hashmap entries */ - rc = jx9JsonSerialize(pObj,pOut); - }else{ - SyBlob *pContents = &pObj->sBlob; - /* Get a printable representation of the contents */ - if((pObj->iFlags & MEMOBJ_STRING) == 0 ){ - MemObjStringValue(&(*pOut), &(*pObj)); - }else{ - /* Append length first */ - SyBlobFormat(&(*pOut), "%u '", SyBlobLength(&pObj->sBlob)); - if( SyBlobLength(pContents) > 0 ){ - SyBlobAppend(&(*pOut), SyBlobData(pContents), SyBlobLength(pContents)); - } - SyBlobAppend(&(*pOut), "'", sizeof(char)); - } - } - SyBlobAppend(&(*pOut), ")", sizeof(char)); - } -#ifdef __WINNT__ - SyBlobAppend(&(*pOut), "\r\n", sizeof("\r\n")-1); -#else - SyBlobAppend(&(*pOut), "\n", sizeof(char)); -#endif - return rc; -} -/* - * ---------------------------------------------------------- - * File: jx9_parse.c - * MD5: d8fcac4c6cd7672f0103c0bf4a4b61fc - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: parse.c v1.2 FreeBSD 2012-12-11 00:46 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* Expression parser for the Jx9 programming language */ -/* Operators associativity */ -#define EXPR_OP_ASSOC_LEFT 0x01 /* Left associative operator */ -#define EXPR_OP_ASSOC_RIGHT 0x02 /* Right associative operator */ -#define EXPR_OP_NON_ASSOC 0x04 /* Non-associative operator */ -/* - * Operators table - * This table is sorted by operators priority (highest to lowest) according - * the JX9 language reference manual. - * JX9 implements all the 60 JX9 operators and have introduced the eq and ne operators. - * The operators precedence table have been improved dramatically so that you can do same - * amazing things now such as array dereferencing, on the fly function call, anonymous function - * as array values, object member access on instantiation and so on. - * Refer to the following page for a full discussion on these improvements: - * http://jx9.symisc.net/features.html - */ -static const jx9_expr_op aOpTable[] = { - /* Postfix operators */ - /* Precedence 2(Highest), left-associative */ - { {".", sizeof(char)}, EXPR_OP_DOT, 2, EXPR_OP_ASSOC_LEFT , JX9_OP_MEMBER }, - { {"[", sizeof(char)}, EXPR_OP_SUBSCRIPT, 2, EXPR_OP_ASSOC_LEFT , JX9_OP_LOAD_IDX}, - /* Precedence 3, non-associative */ - { {"++", sizeof(char)*2}, EXPR_OP_INCR, 3, EXPR_OP_NON_ASSOC , JX9_OP_INCR}, - { {"--", sizeof(char)*2}, EXPR_OP_DECR, 3, EXPR_OP_NON_ASSOC , JX9_OP_DECR}, - /* Unary operators */ - /* Precedence 4, right-associative */ - { {"-", sizeof(char)}, EXPR_OP_UMINUS, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_UMINUS }, - { {"+", sizeof(char)}, EXPR_OP_UPLUS, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_UPLUS }, - { {"~", sizeof(char)}, EXPR_OP_BITNOT, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_BITNOT }, - { {"!", sizeof(char)}, EXPR_OP_LOGNOT, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_LNOT }, - /* Cast operators */ - { {"(int)", sizeof("(int)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_INT }, - { {"(bool)", sizeof("(bool)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_BOOL }, - { {"(string)", sizeof("(string)")-1}, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_STR }, - { {"(float)", sizeof("(float)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_REAL }, - { {"(array)", sizeof("(array)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_ARRAY }, /* Not used, but reserved for future use */ - { {"(object)", sizeof("(object)")-1 }, EXPR_OP_TYPECAST, 4, EXPR_OP_ASSOC_RIGHT, JX9_OP_CVT_ARRAY }, /* Not used, but reserved for future use */ - /* Binary operators */ - /* Precedence 7, left-associative */ - { {"*", sizeof(char)}, EXPR_OP_MUL, 7, EXPR_OP_ASSOC_LEFT , JX9_OP_MUL}, - { {"/", sizeof(char)}, EXPR_OP_DIV, 7, EXPR_OP_ASSOC_LEFT , JX9_OP_DIV}, - { {"%", sizeof(char)}, EXPR_OP_MOD, 7, EXPR_OP_ASSOC_LEFT , JX9_OP_MOD}, - /* Precedence 8, left-associative */ - { {"+", sizeof(char)}, EXPR_OP_ADD, 8, EXPR_OP_ASSOC_LEFT, JX9_OP_ADD}, - { {"-", sizeof(char)}, EXPR_OP_SUB, 8, EXPR_OP_ASSOC_LEFT, JX9_OP_SUB}, - { {"..", sizeof(char)*2},EXPR_OP_DDOT, 8, EXPR_OP_ASSOC_LEFT, JX9_OP_CAT}, - /* Precedence 9, left-associative */ - { {"<<", sizeof(char)*2}, EXPR_OP_SHL, 9, EXPR_OP_ASSOC_LEFT, JX9_OP_SHL}, - { {">>", sizeof(char)*2}, EXPR_OP_SHR, 9, EXPR_OP_ASSOC_LEFT, JX9_OP_SHR}, - /* Precedence 10, non-associative */ - { {"<", sizeof(char)}, EXPR_OP_LT, 10, EXPR_OP_NON_ASSOC, JX9_OP_LT}, - { {">", sizeof(char)}, EXPR_OP_GT, 10, EXPR_OP_NON_ASSOC, JX9_OP_GT}, - { {"<=", sizeof(char)*2}, EXPR_OP_LE, 10, EXPR_OP_NON_ASSOC, JX9_OP_LE}, - { {">=", sizeof(char)*2}, EXPR_OP_GE, 10, EXPR_OP_NON_ASSOC, JX9_OP_GE}, - { {"<>", sizeof(char)*2}, EXPR_OP_NE, 10, EXPR_OP_NON_ASSOC, JX9_OP_NEQ}, - /* Precedence 11, non-associative */ - { {"==", sizeof(char)*2}, EXPR_OP_EQ, 11, EXPR_OP_NON_ASSOC, JX9_OP_EQ}, - { {"!=", sizeof(char)*2}, EXPR_OP_NE, 11, EXPR_OP_NON_ASSOC, JX9_OP_NEQ}, - { {"===", sizeof(char)*3}, EXPR_OP_TEQ, 11, EXPR_OP_NON_ASSOC, JX9_OP_TEQ}, - { {"!==", sizeof(char)*3}, EXPR_OP_TNE, 11, EXPR_OP_NON_ASSOC, JX9_OP_TNE}, - /* Precedence 12, left-associative */ - { {"&", sizeof(char)}, EXPR_OP_BAND, 12, EXPR_OP_ASSOC_LEFT, JX9_OP_BAND}, - /* Binary operators */ - /* Precedence 13, left-associative */ - { {"^", sizeof(char)}, EXPR_OP_XOR, 13, EXPR_OP_ASSOC_LEFT, JX9_OP_BXOR}, - /* Precedence 14, left-associative */ - { {"|", sizeof(char)}, EXPR_OP_BOR, 14, EXPR_OP_ASSOC_LEFT, JX9_OP_BOR}, - /* Precedence 15, left-associative */ - { {"&&", sizeof(char)*2}, EXPR_OP_LAND, 15, EXPR_OP_ASSOC_LEFT, JX9_OP_LAND}, - /* Precedence 16, left-associative */ - { {"||", sizeof(char)*2}, EXPR_OP_LOR, 16, EXPR_OP_ASSOC_LEFT, JX9_OP_LOR}, - /* Ternary operator */ - /* Precedence 17, left-associative */ - { {"?", sizeof(char)}, EXPR_OP_QUESTY, 17, EXPR_OP_ASSOC_LEFT, 0}, - /* Combined binary operators */ - /* Precedence 18, right-associative */ - { {"=", sizeof(char)}, EXPR_OP_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_STORE}, - { {"+=", sizeof(char)*2}, EXPR_OP_ADD_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_ADD_STORE }, - { {"-=", sizeof(char)*2}, EXPR_OP_SUB_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_SUB_STORE }, - { {".=", sizeof(char)*2}, EXPR_OP_DOT_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_CAT_STORE }, - { {"*=", sizeof(char)*2}, EXPR_OP_MUL_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_MUL_STORE }, - { {"/=", sizeof(char)*2}, EXPR_OP_DIV_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_DIV_STORE }, - { {"%=", sizeof(char)*2}, EXPR_OP_MOD_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_MOD_STORE }, - { {"&=", sizeof(char)*2}, EXPR_OP_AND_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_BAND_STORE }, - { {"|=", sizeof(char)*2}, EXPR_OP_OR_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_BOR_STORE }, - { {"^=", sizeof(char)*2}, EXPR_OP_XOR_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_BXOR_STORE }, - { {"<<=", sizeof(char)*3}, EXPR_OP_SHL_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_SHL_STORE }, - { {">>=", sizeof(char)*3}, EXPR_OP_SHR_ASSIGN, 18, EXPR_OP_ASSOC_RIGHT, JX9_OP_SHR_STORE }, - /* Precedence 22, left-associative [Lowest operator] */ - { {",", sizeof(char)}, EXPR_OP_COMMA, 22, EXPR_OP_ASSOC_LEFT, 0}, /* IMP-0139-COMMA: Symisc eXtension */ -}; -/* Function call operator need special handling */ -static const jx9_expr_op sFCallOp = {{"(", sizeof(char)}, EXPR_OP_FUNC_CALL, 2, EXPR_OP_ASSOC_LEFT , JX9_OP_CALL}; -/* - * Check if the given token is a potential operator or not. - * This function is called by the lexer each time it extract a token that may - * look like an operator. - * Return a structure [i.e: jx9_expr_op instnace ] that describe the operator on success. - * Otherwise NULL. - * Note that the function take care of handling ambiguity [i.e: whether we are dealing with - * a binary minus or unary minus.] - */ -JX9_PRIVATE const jx9_expr_op * jx9ExprExtractOperator(SyString *pStr, SyToken *pLast) -{ - sxu32 n = 0; - sxi32 rc; - /* Do a linear lookup on the operators table */ - for(;;){ - if( n >= SX_ARRAYSIZE(aOpTable) ){ - break; - } - rc = SyStringCmp(pStr, &aOpTable[n].sOp, SyMemcmp); - if( rc == 0 ){ - if( aOpTable[n].sOp.nByte != sizeof(char) || (aOpTable[n].iOp != EXPR_OP_UMINUS && aOpTable[n].iOp != EXPR_OP_UPLUS) || pLast == 0 ){ - if( aOpTable[n].iOp == EXPR_OP_SUBSCRIPT && (pLast == 0 || (pLast->nType & (JX9_TK_ID|JX9_TK_CSB/*]*/|JX9_TK_RPAREN/*)*/)) == 0) ){ - /* JSON Array not subscripting, return NULL */ - return 0; - } - /* There is no ambiguity here, simply return the first operator seen */ - return &aOpTable[n]; - } - /* Handle ambiguity */ - if( pLast->nType & (JX9_TK_LPAREN/*'('*/|JX9_TK_OCB/*'{'*/|JX9_TK_OSB/*'['*/|JX9_TK_COLON/*:*/|JX9_TK_COMMA/*, '*/) ){ - /* Unary opertors have prcedence here over binary operators */ - return &aOpTable[n]; - } - if( pLast->nType & JX9_TK_OP ){ - const jx9_expr_op *pOp = (const jx9_expr_op *)pLast->pUserData; - /* Ticket 1433-31: Handle the '++', '--' operators case */ - if( pOp->iOp != EXPR_OP_INCR && pOp->iOp != EXPR_OP_DECR ){ - /* Unary opertors have prcedence here over binary operators */ - return &aOpTable[n]; - } - - } - } - ++n; /* Next operator in the table */ - } - /* No such operator */ - return 0; -} -/* - * Delimit a set of token stream. - * This function take care of handling the nesting level and stops when it hit - * the end of the input or the ending token is found and the nesting level is zero. - */ -JX9_PRIVATE void jx9DelimitNestedTokens(SyToken *pIn,SyToken *pEnd,sxu32 nTokStart,sxu32 nTokEnd,SyToken **ppEnd) -{ - SyToken *pCur = pIn; - sxi32 iNest = 1; - for(;;){ - if( pCur >= pEnd ){ - break; - } - if( pCur->nType & nTokStart ){ - /* Increment nesting level */ - iNest++; - }else if( pCur->nType & nTokEnd ){ - /* Decrement nesting level */ - iNest--; - if( iNest <= 0 ){ - break; - } - } - /* Advance cursor */ - pCur++; - } - /* Point to the end of the chunk */ - *ppEnd = pCur; -} -/* - * Retrun TRUE if the given ID represent a language construct [i.e: print, print..]. FALSE otherwise. - * Note on reserved keywords. - * According to the JX9 language reference manual: - * These words have special meaning in JX9. Some of them represent things which look like - * functions, some look like constants, and so on--but they're not, really: they are language - * constructs. You cannot use any of the following words as constants, object names, function - * or method names. Using them as variable names is generally OK, but could lead to confusion. - */ -JX9_PRIVATE int jx9IsLangConstruct(sxu32 nKeyID) -{ - if( nKeyID == JX9_TKWRD_PRINT || nKeyID == JX9_TKWRD_EXIT || nKeyID == JX9_TKWRD_DIE - || nKeyID == JX9_TKWRD_INCLUDE|| nKeyID == JX9_TKWRD_IMPORT ){ - return TRUE; - } - /* Not a language construct */ - return FALSE; -} -/* - * Point to the next expression that should be evaluated shortly. - * The cursor stops when it hit a comma ', ' or a semi-colon and the nesting - * level is zero. - */ -JX9_PRIVATE sxi32 jx9GetNextExpr(SyToken *pStart,SyToken *pEnd,SyToken **ppNext) -{ - SyToken *pCur = pStart; - sxi32 iNest = 0; - if( pCur >= pEnd || (pCur->nType & JX9_TK_SEMI/*';'*/) ){ - /* Last expression */ - return SXERR_EOF; - } - while( pCur < pEnd ){ - if( (pCur->nType & (JX9_TK_COMMA/*','*/|JX9_TK_SEMI/*';'*/)) && iNest <= 0){ - break; - } - if( pCur->nType & (JX9_TK_LPAREN/*'('*/|JX9_TK_OSB/*'['*/|JX9_TK_OCB/*'{'*/) ){ - iNest++; - }else if( pCur->nType & (JX9_TK_RPAREN/*')'*/|JX9_TK_CSB/*']'*/|JX9_TK_CCB/*'}*/) ){ - iNest--; - } - pCur++; - } - *ppNext = pCur; - return SXRET_OK; -} -/* - * Collect and assemble tokens holding annonymous functions/closure body. - * When errors, JX9 take care of generating the appropriate error message. - * Note on annonymous functions. - * According to the JX9 language reference manual: - * Anonymous functions, also known as closures, allow the creation of functions - * which have no specified name. They are most useful as the value of callback - * parameters, but they have many other uses. - * Closures may also inherit variables from the parent scope. Any such variables - * must be declared in the function header. Inheriting variables from the parent - * scope is not the same as using global variables. Global variables exist in the global scope - * which is the same no matter what function is executing. The parent scope of a closure is the - * function in which the closure was declared (not necessarily the function it was called from). - * - * Some example: - * $greet = function($name) - * { - * printf("Hello %s\r\n", $name); - * }; - * $greet('World'); - * $greet('JX9'); - * - * $double = function($a) { - * return $a * 2; - * }; - * // This is our range of numbers - * $numbers = range(1, 5); - * // Use the Annonymous function as a callback here to - * // double the size of each element in our - * // range - * $new_numbers = array_map($double, $numbers); - * print implode(' ', $new_numbers); - */ -static sxi32 ExprAssembleAnnon(jx9_gen_state *pGen,SyToken **ppCur, SyToken *pEnd) -{ - SyToken *pIn = *ppCur; - sxu32 nLine; - sxi32 rc; - /* Jump the 'function' keyword */ - nLine = pIn->nLine; - pIn++; - if( pIn < pEnd && (pIn->nType & (JX9_TK_ID|JX9_TK_KEYWORD)) ){ - pIn++; - } - if( pIn >= pEnd || (pIn->nType & JX9_TK_LPAREN) == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Missing opening parenthesis '(' while declaring annonymous function"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - goto Synchronize; - } - pIn++; /* Jump the leading parenthesis '(' */ - jx9DelimitNestedTokens(pIn, pEnd, JX9_TK_LPAREN/*'('*/, JX9_TK_RPAREN/*')'*/, &pIn); - if( pIn >= pEnd || &pIn[1] >= pEnd ){ - /* Syntax error */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Syntax error while declaring annonymous function"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - goto Synchronize; - } - pIn++; /* Jump the trailing parenthesis */ - if( pIn->nType & JX9_TK_OCB /*'{'*/ ){ - pIn++; /* Jump the leading curly '{' */ - jx9DelimitNestedTokens(pIn, pEnd, JX9_TK_OCB/*'{'*/, JX9_TK_CCB/*'}'*/, &pIn); - if( pIn < pEnd ){ - pIn++; - } - }else{ - /* Syntax error */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, nLine, "Syntax error while declaring annonymous function, missing '{'"); - if( rc == SXERR_ABORT ){ - return SXERR_ABORT; - } - } - rc = SXRET_OK; -Synchronize: - /* Synchronize pointers */ - *ppCur = pIn; - return rc; -} -/* - * Make sure we are dealing with a valid expression tree. - * This function check for balanced parenthesis, braces, brackets and so on. - * When errors, JX9 take care of generating the appropriate error message. - * Return SXRET_OK on success. Any other return value indicates syntax error. - */ -static sxi32 ExprVerifyNodes(jx9_gen_state *pGen, jx9_expr_node **apNode, sxi32 nNode) -{ - sxi32 iParen, iSquare, iBraces; - sxi32 i, rc; - - if( nNode > 0 && apNode[0]->pOp && (apNode[0]->pOp->iOp == EXPR_OP_ADD || apNode[0]->pOp->iOp == EXPR_OP_SUB) ){ - /* Fix and mark as an unary not binary plus/minus operator */ - apNode[0]->pOp = jx9ExprExtractOperator(&apNode[0]->pStart->sData, 0); - apNode[0]->pStart->pUserData = (void *)apNode[0]->pOp; - } - iParen = iSquare = iBraces = 0; - for( i = 0 ; i < nNode ; ++i ){ - if( apNode[i]->pStart->nType & JX9_TK_LPAREN /*'('*/){ - if( i > 0 && ( apNode[i-1]->xCode == jx9CompileVariable || apNode[i-1]->xCode == jx9CompileLiteral || - (apNode[i - 1]->pStart->nType & (JX9_TK_ID|JX9_TK_KEYWORD|JX9_TK_SSTR|JX9_TK_DSTR|JX9_TK_RPAREN/*')'*/|JX9_TK_CSB/*]*/))) ){ - /* Ticket 1433-033: Take care to ignore alpha-stream [i.e: or, xor] operators followed by an opening parenthesis */ - if( (apNode[i - 1]->pStart->nType & JX9_TK_OP) == 0 ){ - /* We are dealing with a postfix [i.e: function call] operator - * not a simple left parenthesis. Mark the node. - */ - apNode[i]->pStart->nType |= JX9_TK_OP; - apNode[i]->pStart->pUserData = (void *)&sFCallOp; /* Function call operator */ - apNode[i]->pOp = &sFCallOp; - } - } - iParen++; - }else if( apNode[i]->pStart->nType & JX9_TK_RPAREN/*')*/){ - if( iParen <= 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token ')'"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - iParen--; - }else if( apNode[i]->pStart->nType & JX9_TK_OSB /*'['*/ && apNode[i]->xCode == 0 ){ - iSquare++; - }else if (apNode[i]->pStart->nType & JX9_TK_CSB /*']'*/){ - if( iSquare <= 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token ']'"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - iSquare--; - }else if( apNode[i]->pStart->nType & JX9_TK_OCB /*'{'*/ && apNode[i]->xCode == 0 ){ - iBraces++; - }else if (apNode[i]->pStart->nType & JX9_TK_CCB /*'}'*/){ - if( iBraces <= 0 ){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[i]->pStart->nLine, "Syntax error: Unexpected token '}'"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - iBraces--; - }else if( apNode[i]->pStart->nType & JX9_TK_OP ){ - const jx9_expr_op *pOp = (const jx9_expr_op *)apNode[i]->pOp; - if( i > 0 && (pOp->iOp == EXPR_OP_UMINUS || pOp->iOp == EXPR_OP_UPLUS)){ - if( apNode[i-1]->xCode == jx9CompileVariable || apNode[i-1]->xCode == jx9CompileLiteral ){ - sxi32 iExprOp = EXPR_OP_SUB; /* Binary minus */ - sxu32 n = 0; - if( pOp->iOp == EXPR_OP_UPLUS ){ - iExprOp = EXPR_OP_ADD; /* Binary plus */ - } - /* - * TICKET 1433-013: This is a fix around an obscure bug when the user uses - * a variable name which is an alpha-stream operator [i.e: $and, $xor, $eq..]. - */ - while( n < SX_ARRAYSIZE(aOpTable) && aOpTable[n].iOp != iExprOp ){ - ++n; - } - pOp = &aOpTable[n]; - /* Mark as binary '+' or '-', not an unary */ - apNode[i]->pOp = pOp; - apNode[i]->pStart->pUserData = (void *)pOp; - } - } - } - } - if( iParen != 0 || iSquare != 0 || iBraces != 0){ - rc = jx9GenCompileError(&(*pGen), E_ERROR, apNode[0]->pStart->nLine, "Syntax error, mismatched '(', '[' or '{'"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - return SXRET_OK; -} -/* - * Extract a single expression node from the input. - * On success store the freshly extractd node in ppNode. - * When errors, JX9 take care of generating the appropriate error message. - * An expression node can be a variable [i.e: $var], an operator [i.e: ++] - * an annonymous function [i.e: function(){ return "Hello"; }, a double/single - * quoted string, a heredoc/nowdoc, a literal [i.e: JX9_EOL], a namespace path - * [i.e: namespaces\path\to..], a array/list [i.e: array(4, 5, 6)] and so on. - */ -static sxi32 ExprExtractNode(jx9_gen_state *pGen, jx9_expr_node **ppNode) -{ - jx9_expr_node *pNode; - SyToken *pCur; - sxi32 rc; - /* Allocate a new node */ - pNode = (jx9_expr_node *)SyMemBackendPoolAlloc(&pGen->pVm->sAllocator, sizeof(jx9_expr_node)); - if( pNode == 0 ){ - /* If the supplied memory subsystem is so sick that we are unable to allocate - * a tiny chunk of memory, there is no much we can do here. - */ - return SXERR_MEM; - } - /* Zero the structure */ - SyZero(pNode, sizeof(jx9_expr_node)); - SySetInit(&pNode->aNodeArgs, &pGen->pVm->sAllocator, sizeof(jx9_expr_node **)); - /* Point to the head of the token stream */ - pCur = pNode->pStart = pGen->pIn; - /* Start collecting tokens */ - if( pCur->nType & JX9_TK_OP ){ - /* Point to the instance that describe this operator */ - pNode->pOp = (const jx9_expr_op *)pCur->pUserData; - /* Advance the stream cursor */ - pCur++; - }else if( pCur->nType & JX9_TK_DOLLAR ){ - /* Isolate variable */ - pCur++; /* Jump the dollar sign */ - if( pCur >= pGen->pEnd ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"Invalid variable name"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); - return rc; - } - pCur++; /* Jump the variable name */ - pNode->xCode = jx9CompileVariable; - }else if( pCur->nType & JX9_TK_OCB /* '{' */ ){ - /* JSON Object, assemble tokens */ - pCur++; - jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_OCB /* '[' */, JX9_TK_CCB /* ']' */, &pCur); - if( pCur < pGen->pEnd ){ - pCur++; - }else{ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"JSON Object: Missing closing braces '}'"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); - return rc; - } - pNode->xCode = jx9CompileJsonObject; - }else if( pCur->nType & JX9_TK_OSB /* '[' */ && !(pCur->nType & JX9_TK_OP) ){ - /* JSON Array, assemble tokens */ - pCur++; - jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_OSB /* '[' */, JX9_TK_CSB /* ']' */, &pCur); - if( pCur < pGen->pEnd ){ - pCur++; - }else{ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine,"JSON Array: Missing closing square bracket ']'"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); - return rc; - } - pNode->xCode = jx9CompileJsonArray; - }else if( pCur->nType & JX9_TK_KEYWORD ){ - int nKeyword = SX_PTR_TO_INT(pCur->pUserData); - if( nKeyword == JX9_TKWRD_FUNCTION ){ - /* Annonymous function */ - if( &pCur[1] >= pGen->pEnd ){ - /* Assume a literal */ - pCur++; - pNode->xCode = jx9CompileLiteral; - }else{ - /* Assemble annonymous functions body */ - rc = ExprAssembleAnnon(&(*pGen), &pCur, pGen->pEnd); - if( rc != SXRET_OK ){ - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); - return rc; - } - pNode->xCode = jx9CompileAnnonFunc; - } - }else if( jx9IsLangConstruct(nKeyword) && &pCur[1] < pGen->pEnd ){ - /* Language constructs [i.e: print,die...] require special handling */ - jx9DelimitNestedTokens(pCur, pGen->pEnd, JX9_TK_LPAREN|JX9_TK_OCB|JX9_TK_OSB, JX9_TK_RPAREN|JX9_TK_CCB|JX9_TK_CSB, &pCur); - pNode->xCode = jx9CompileLangConstruct; - }else{ - /* Assume a literal */ - pCur++; - pNode->xCode = jx9CompileLiteral; - } - }else if( pCur->nType & (JX9_TK_ID) ){ - /* Constants, function name, namespace path, object name... */ - pCur++; - pNode->xCode = jx9CompileLiteral; - }else{ - if( (pCur->nType & (JX9_TK_LPAREN|JX9_TK_RPAREN|JX9_TK_COMMA|JX9_TK_CSB|JX9_TK_OCB|JX9_TK_CCB|JX9_TK_COLON)) == 0 ){ - /* Point to the code generator routine */ - pNode->xCode = jx9GetNodeHandler(pCur->nType); - if( pNode->xCode == 0 ){ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Syntax error: Unexpected token '%z'", &pNode->pStart->sData); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); - return rc; - } - } - /* Advance the stream cursor */ - pCur++; - } - /* Point to the end of the token stream */ - pNode->pEnd = pCur; - /* Save the node for later processing */ - *ppNode = pNode; - /* Synchronize cursors */ - pGen->pIn = pCur; - return SXRET_OK; -} -/* - * Free an expression tree. - */ -static void ExprFreeTree(jx9_gen_state *pGen, jx9_expr_node *pNode) -{ - if( pNode->pLeft ){ - /* Release the left tree */ - ExprFreeTree(&(*pGen), pNode->pLeft); - } - if( pNode->pRight ){ - /* Release the right tree */ - ExprFreeTree(&(*pGen), pNode->pRight); - } - if( pNode->pCond ){ - /* Release the conditional tree used by the ternary operator */ - ExprFreeTree(&(*pGen), pNode->pCond); - } - if( SySetUsed(&pNode->aNodeArgs) > 0 ){ - jx9_expr_node **apArg; - sxu32 n; - /* Release node arguments */ - apArg = (jx9_expr_node **)SySetBasePtr(&pNode->aNodeArgs); - for( n = 0 ; n < SySetUsed(&pNode->aNodeArgs) ; ++n ){ - ExprFreeTree(&(*pGen), apArg[n]); - } - SySetRelease(&pNode->aNodeArgs); - } - /* Finally, release this node */ - SyMemBackendPoolFree(&pGen->pVm->sAllocator, pNode); -} -/* - * Free an expression tree. - * This function is a wrapper around ExprFreeTree() defined above. - */ -JX9_PRIVATE sxi32 jx9ExprFreeTree(jx9_gen_state *pGen, SySet *pNodeSet) -{ - jx9_expr_node **apNode; - sxu32 n; - apNode = (jx9_expr_node **)SySetBasePtr(pNodeSet); - for( n = 0 ; n < SySetUsed(pNodeSet) ; ++n ){ - if( apNode[n] ){ - ExprFreeTree(&(*pGen), apNode[n]); - } - } - return SXRET_OK; -} -/* - * Check if the given node is a modifialbe l/r-value. - * Return TRUE if modifiable.FALSE otherwise. - */ -static int ExprIsModifiableValue(jx9_expr_node *pNode) -{ - sxi32 iExprOp; - if( pNode->pOp == 0 ){ - return pNode->xCode == jx9CompileVariable ? TRUE : FALSE; - } - iExprOp = pNode->pOp->iOp; - if( iExprOp == EXPR_OP_DOT /*'.' */ ){ - return TRUE; - } - if( iExprOp == EXPR_OP_SUBSCRIPT/*'[]'*/ ){ - if( pNode->pLeft->pOp ) { - if( pNode->pLeft->pOp->iOp != EXPR_OP_SUBSCRIPT /*'['*/ && pNode->pLeft->pOp->iOp != EXPR_OP_DOT /*'.'*/){ - return FALSE; - } - }else if( pNode->pLeft->xCode != jx9CompileVariable ){ - return FALSE; - } - return TRUE; - } - /* Not a modifiable l or r-value */ - return FALSE; -} -/* Forward declaration */ -static sxi32 ExprMakeTree(jx9_gen_state *pGen, jx9_expr_node **apNode, sxi32 nToken); -/* Macro to check if the given node is a terminal */ -#define NODE_ISTERM(NODE) (apNode[NODE] && (!apNode[NODE]->pOp || apNode[NODE]->pLeft )) -/* - * Buid an expression tree for each given function argument. - * When errors, JX9 take care of generating the appropriate error message. - */ -static sxi32 ExprProcessFuncArguments(jx9_gen_state *pGen, jx9_expr_node *pOp, jx9_expr_node **apNode, sxi32 nToken) -{ - sxi32 iNest, iCur, iNode; - sxi32 rc; - /* Process function arguments from left to right */ - iCur = 0; - for(;;){ - if( iCur >= nToken ){ - /* No more arguments to process */ - break; - } - iNode = iCur; - iNest = 0; - while( iCur < nToken ){ - if( apNode[iCur] ){ - if( (apNode[iCur]->pStart->nType & JX9_TK_COMMA) && apNode[iCur]->pLeft == 0 && iNest <= 0 ){ - break; - }else if( apNode[iCur]->pStart->nType & (JX9_TK_LPAREN|JX9_TK_OSB|JX9_TK_OCB) ){ - iNest++; - }else if( apNode[iCur]->pStart->nType & (JX9_TK_RPAREN|JX9_TK_CCB|JX9_TK_CSB) ){ - iNest--; - } - } - iCur++; - } - if( iCur > iNode ){ - ExprMakeTree(&(*pGen), &apNode[iNode], iCur-iNode); - if( apNode[iNode] ){ - /* Put a pointer to the root of the tree in the arguments set */ - SySetPut(&pOp->aNodeArgs, (const void *)&apNode[iNode]); - }else{ - /* Empty function argument */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pOp->pStart->nLine, "Empty function argument"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - }else{ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pOp->pStart->nLine, "Missing function argument"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - /* Jump trailing comma */ - if( iCur < nToken && apNode[iCur] && (apNode[iCur]->pStart->nType & JX9_TK_COMMA) ){ - iCur++; - if( iCur >= nToken ){ - /* missing function argument */ - rc = jx9GenCompileError(&(*pGen), E_ERROR, pOp->pStart->nLine, "Missing function argument"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - } - } - return SXRET_OK; -} -/* - * Create an expression tree from an array of tokens. - * If successful, the root of the tree is stored in apNode[0]. - * When errors, JX9 take care of generating the appropriate error message. - */ - static sxi32 ExprMakeTree(jx9_gen_state *pGen, jx9_expr_node **apNode, sxi32 nToken) - { - sxi32 i, iLeft, iRight; - jx9_expr_node *pNode; - sxi32 iCur; - sxi32 rc; - if( nToken <= 0 || (nToken == 1 && apNode[0]->xCode) ){ - /* TICKET 1433-17: self evaluating node */ - return SXRET_OK; - } - /* Process expressions enclosed in parenthesis first */ - for( iCur = 0 ; iCur < nToken ; ++iCur ){ - sxi32 iNest; - /* Note that, we use strict comparison here '!=' instead of the bitwise and '&' operator - * since the LPAREN token can also be an operator [i.e: Function call]. - */ - if( apNode[iCur] == 0 || apNode[iCur]->pStart->nType != JX9_TK_LPAREN ){ - continue; - } - iNest = 1; - iLeft = iCur; - /* Find the closing parenthesis */ - iCur++; - while( iCur < nToken ){ - if( apNode[iCur] ){ - if( apNode[iCur]->pStart->nType & JX9_TK_RPAREN /* ')' */){ - /* Decrement nesting level */ - iNest--; - if( iNest <= 0 ){ - break; - } - }else if( apNode[iCur]->pStart->nType & JX9_TK_LPAREN /* '(' */ ){ - /* Increment nesting level */ - iNest++; - } - } - iCur++; - } - if( iCur - iLeft > 1 ){ - /* Recurse and process this expression */ - rc = ExprMakeTree(&(*pGen), &apNode[iLeft + 1], iCur - iLeft - 1); - if( rc != SXRET_OK ){ - return rc; - } - } - /* Free the left and right nodes */ - ExprFreeTree(&(*pGen), apNode[iLeft]); - ExprFreeTree(&(*pGen), apNode[iCur]); - apNode[iLeft] = 0; - apNode[iCur] = 0; - } - /* Handle postfix [i.e: function call, member access] operators with precedence 2 */ - iLeft = -1; - for( iCur = 0 ; iCur < nToken ; ++iCur ){ - if( apNode[iCur] == 0 ){ - continue; - } - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iPrec == 2 && pNode->pLeft == 0 ){ - if( pNode->pOp->iOp == EXPR_OP_FUNC_CALL ){ - /* Collect function arguments */ - sxi32 iPtr = 0; - sxi32 nFuncTok = 0; - while( nFuncTok + iCur < nToken ){ - if( apNode[nFuncTok+iCur] ){ - if( apNode[nFuncTok+iCur]->pStart->nType & JX9_TK_LPAREN /*'('*/ ){ - iPtr++; - }else if ( apNode[nFuncTok+iCur]->pStart->nType & JX9_TK_RPAREN /*')'*/){ - iPtr--; - if( iPtr <= 0 ){ - break; - } - } - } - nFuncTok++; - } - if( nFuncTok + iCur >= nToken ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Missing right parenthesis ')'"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - if( iLeft < 0 || !NODE_ISTERM(iLeft) /*|| ( apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec != 2)*/ ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "Invalid function name"); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - if( nFuncTok > 1 ){ - /* Process function arguments */ - rc = ExprProcessFuncArguments(&(*pGen), pNode, &apNode[iCur+1], nFuncTok-1); - if( rc != SXRET_OK ){ - return rc; - } - } - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - apNode[iLeft] = 0; - for( iPtr = 1; iPtr <= nFuncTok ; iPtr++ ){ - apNode[iCur+iPtr] = 0; - } - }else if (pNode->pOp->iOp == EXPR_OP_SUBSCRIPT ){ - /* Subscripting */ - sxi32 iArrTok = iCur + 1; - sxi32 iNest = 1; - if( iLeft >= 0 && (apNode[iLeft]->xCode == jx9CompileVariable || (apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec == 2 /* postfix */) ) ){ - /* Collect index tokens */ - while( iArrTok < nToken ){ - if( apNode[iArrTok] ){ - if( apNode[iArrTok]->pStart->nType & JX9_TK_OSB /*'['*/){ - /* Increment nesting level */ - iNest++; - }else if( apNode[iArrTok]->pStart->nType & JX9_TK_CSB /*']'*/){ - /* Decrement nesting level */ - iNest--; - if( iNest <= 0 ){ - break; - } - } - } - ++iArrTok; - } - if( iArrTok > iCur + 1 ){ - /* Recurse and process this expression */ - rc = ExprMakeTree(&(*pGen), &apNode[iCur+1], iArrTok - iCur - 1); - if( rc != SXRET_OK ){ - return rc; - } - /* Link the node to it's index */ - SySetPut(&pNode->aNodeArgs, (const void *)&apNode[iCur+1]); - } - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - pNode->pRight = 0; - apNode[iLeft] = 0; - for( iNest = iCur + 1 ; iNest <= iArrTok ; ++iNest ){ - apNode[iNest] = 0; - } - } - }else{ - /* Member access operators [i.e: '.' ] */ - iRight = iCur + 1; - while( iRight < nToken && apNode[iRight] == 0 ){ - iRight++; - } - if( iRight >= nToken || iLeft < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid member name", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - if( pNode->pLeft->pOp == 0 && pNode->pLeft->xCode != jx9CompileVariable ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, - "'%z': Expecting a variable as left operand", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - pNode->pRight = apNode[iRight]; - apNode[iLeft] = apNode[iRight] = 0; - } - } - iLeft = iCur; - } - /* Handle post/pre icrement/decrement [i.e: ++/--] operators with precedence 3 */ - iLeft = -1; - for( iCur = 0 ; iCur < nToken ; ++iCur ){ - if( apNode[iCur] == 0 ){ - continue; - } - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iPrec == 3 && pNode->pLeft == 0){ - if( iLeft >= 0 && ((apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec == 2 /* Postfix */) - || apNode[iLeft]->xCode == jx9CompileVariable) ){ - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - apNode[iLeft] = 0; - } - } - iLeft = iCur; - } - iLeft = -1; - for( iCur = nToken - 1 ; iCur >= 0 ; iCur-- ){ - if( apNode[iCur] == 0 ){ - continue; - } - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iPrec == 3 && pNode->pLeft == 0){ - if( iLeft < 0 || (apNode[iLeft]->pOp == 0 && apNode[iLeft]->xCode != jx9CompileVariable) - || ( apNode[iLeft]->pOp && apNode[iLeft]->pOp->iPrec != 2 /* Postfix */) ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z' operator needs l-value", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - apNode[iLeft] = 0; - /* Mark as pre-increment/decrement node */ - pNode->iFlags |= EXPR_NODE_PRE_INCR; - } - iLeft = iCur; - } - /* Handle right associative unary and cast operators [i.e: !, (string), ~...] with precedence 4 */ - iLeft = 0; - for( iCur = nToken - 1 ; iCur >= 0 ; iCur-- ){ - if( apNode[iCur] ){ - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iPrec == 4 && pNode->pLeft == 0){ - if( iLeft > 0 ){ - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - apNode[iLeft] = 0; - if( pNode->pLeft && pNode->pLeft->pOp && pNode->pLeft->pOp->iPrec > 4 ){ - if( pNode->pLeft->pLeft == 0 || pNode->pLeft->pRight == 0 ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pLeft->pStart->nLine, "'%z': Missing operand", &pNode->pLeft->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - } - }else{ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing operand", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - } - /* Save terminal position */ - iLeft = iCur; - } - } - /* Process left and non-associative binary operators [i.e: *, /, &&, ||...]*/ - for( i = 7 ; i < 17 ; i++ ){ - iLeft = -1; - for( iCur = 0 ; iCur < nToken ; ++iCur ){ - if( apNode[iCur] == 0 ){ - continue; - } - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iPrec == i && pNode->pLeft == 0 ){ - /* Get the right node */ - iRight = iCur + 1; - while( iRight < nToken && apNode[iRight] == 0 ){ - iRight++; - } - if( iRight >= nToken || iLeft < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid operand", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - pNode->pRight = apNode[iRight]; - apNode[iLeft] = apNode[iRight] = 0; - } - iLeft = iCur; - } - } - /* Handle the ternary operator. (expr1) ? (expr2) : (expr3) - * Note that we do not need a precedence loop here since - * we are dealing with a single operator. - */ - iLeft = -1; - for( iCur = 0 ; iCur < nToken ; ++iCur ){ - if( apNode[iCur] == 0 ){ - continue; - } - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iOp == EXPR_OP_QUESTY && pNode->pLeft == 0 ){ - sxi32 iNest = 1; - if( iLeft < 0 || !NODE_ISTERM(iLeft) ){ - /* Missing condition */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Syntax error", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - /* Get the right node */ - iRight = iCur + 1; - while( iRight < nToken ){ - if( apNode[iRight] ){ - if( apNode[iRight]->pOp && apNode[iRight]->pOp->iOp == EXPR_OP_QUESTY && apNode[iRight]->pCond == 0){ - /* Increment nesting level */ - ++iNest; - }else if( apNode[iRight]->pStart->nType & JX9_TK_COLON /*:*/ ){ - /* Decrement nesting level */ - --iNest; - if( iNest <= 0 ){ - break; - } - } - } - iRight++; - } - if( iRight > iCur + 1 ){ - /* Recurse and process the then expression */ - rc = ExprMakeTree(&(*pGen), &apNode[iCur + 1], iRight - iCur - 1); - if( rc != SXRET_OK ){ - return rc; - } - /* Link the node to the tree */ - pNode->pLeft = apNode[iCur + 1]; - }else{ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing 'then' expression", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - apNode[iCur + 1] = 0; - if( iRight + 1 < nToken ){ - /* Recurse and process the else expression */ - rc = ExprMakeTree(&(*pGen), &apNode[iRight + 1], nToken - iRight - 1); - if( rc != SXRET_OK ){ - return rc; - } - /* Link the node to the tree */ - pNode->pRight = apNode[iRight + 1]; - apNode[iRight + 1] = apNode[iRight] = 0; - }else{ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing 'else' expression", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - /* Point to the condition */ - pNode->pCond = apNode[iLeft]; - apNode[iLeft] = 0; - break; - } - iLeft = iCur; - } - /* Process right associative binary operators [i.e: '=', '+=', '/='] - * Note: All right associative binary operators have precedence 18 - * so there is no need for a precedence loop here. - */ - iRight = -1; - for( iCur = nToken - 1 ; iCur >= 0 ; iCur--){ - if( apNode[iCur] == 0 ){ - continue; - } - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iPrec == 18 && pNode->pLeft == 0 ){ - /* Get the left node */ - iLeft = iCur - 1; - while( iLeft >= 0 && apNode[iLeft] == 0 ){ - iLeft--; - } - if( iLeft < 0 || iRight < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid operand", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - if( ExprIsModifiableValue(apNode[iLeft]) == FALSE ){ - if( pNode->pOp->iVmOp != JX9_OP_STORE ){ - /* Left operand must be a modifiable l-value */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, - "'%z': Left operand must be a modifiable l-value", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - } - /* Link the node to the tree (Reverse) */ - pNode->pLeft = apNode[iRight]; - pNode->pRight = apNode[iLeft]; - apNode[iLeft] = apNode[iRight] = 0; - } - iRight = iCur; - } - /* Process the lowest precedence operator (22, comma) */ - iLeft = -1; - for( iCur = 0 ; iCur < nToken ; ++iCur ){ - if( apNode[iCur] == 0 ){ - continue; - } - pNode = apNode[iCur]; - if( pNode->pOp && pNode->pOp->iPrec == 22 /* ',' */ && pNode->pLeft == 0 ){ - /* Get the right node */ - iRight = iCur + 1; - while( iRight < nToken && apNode[iRight] == 0 ){ - iRight++; - } - if( iRight >= nToken || iLeft < 0 || !NODE_ISTERM(iRight) || !NODE_ISTERM(iLeft) ){ - /* Syntax error */ - rc = jx9GenCompileError(pGen, E_ERROR, pNode->pStart->nLine, "'%z': Missing/Invalid operand", &pNode->pOp->sOp); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - /* Link the node to the tree */ - pNode->pLeft = apNode[iLeft]; - pNode->pRight = apNode[iRight]; - apNode[iLeft] = apNode[iRight] = 0; - } - iLeft = iCur; - } - /* Point to the root of the expression tree */ - for( iCur = 1 ; iCur < nToken ; ++iCur ){ - if( apNode[iCur] ){ - if( (apNode[iCur]->pOp || apNode[iCur]->xCode ) && apNode[0] != 0){ - rc = jx9GenCompileError(pGen, E_ERROR, apNode[iCur]->pStart->nLine, "Unexpected token '%z'", &apNode[iCur]->pStart->sData); - if( rc != SXERR_ABORT ){ - rc = SXERR_SYNTAX; - } - return rc; - } - apNode[0] = apNode[iCur]; - apNode[iCur] = 0; - } - } - return SXRET_OK; - } - /* - * Build an expression tree from the freshly extracted raw tokens. - * If successful, the root of the tree is stored in ppRoot. - * When errors, JX9 take care of generating the appropriate error message. - * This is the public interface used by the most code generator routines. - */ -JX9_PRIVATE sxi32 jx9ExprMakeTree(jx9_gen_state *pGen, SySet *pExprNode, jx9_expr_node **ppRoot) -{ - jx9_expr_node **apNode; - jx9_expr_node *pNode; - sxi32 rc; - /* Reset node container */ - SySetReset(pExprNode); - pNode = 0; /* Prevent compiler warning */ - /* Extract nodes one after one until we hit the end of the input */ - while( pGen->pIn < pGen->pEnd ){ - rc = ExprExtractNode(&(*pGen), &pNode); - if( rc != SXRET_OK ){ - return rc; - } - /* Save the extracted node */ - SySetPut(pExprNode, (const void *)&pNode); - } - if( SySetUsed(pExprNode) < 1 ){ - /* Empty expression [i.e: A semi-colon;] */ - *ppRoot = 0; - return SXRET_OK; - } - apNode = (jx9_expr_node **)SySetBasePtr(pExprNode); - /* Make sure we are dealing with valid nodes */ - rc = ExprVerifyNodes(&(*pGen), apNode, (sxi32)SySetUsed(pExprNode)); - if( rc != SXRET_OK ){ - /* Don't worry about freeing memory, upper layer will - * cleanup the mess left behind. - */ - *ppRoot = 0; - return rc; - } - /* Build the tree */ - rc = ExprMakeTree(&(*pGen), apNode, (sxi32)SySetUsed(pExprNode)); - if( rc != SXRET_OK ){ - /* Something goes wrong [i.e: Syntax error] */ - *ppRoot = 0; - return rc; - } - /* Point to the root of the tree */ - *ppRoot = apNode[0]; - return SXRET_OK; -} -/* - * ---------------------------------------------------------- - * File: jx9_vfs.c - * MD5: 8b73046a366acaf6aa7227c2133e16c0 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: vfs.c v2.1 Ubuntu 2012-12-13 00:013 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* - * This file implement a virtual file systems (VFS) for the JX9 engine. - */ -/* - * Given a string containing the path of a file or directory, this function - * return the parent directory's path. - */ -JX9_PRIVATE const char * jx9ExtractDirName(const char *zPath, int nByte, int *pLen) -{ - const char *zEnd = &zPath[nByte - 1]; - int c, d; - c = d = '/'; -#ifdef __WINNT__ - d = '\\'; -#endif - while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){ - zEnd--; - } - *pLen = (int)(zEnd-zPath); -#ifdef __WINNT__ - if( (*pLen) == (int)sizeof(char) && zPath[0] == '/' ){ - /* Normalize path on windows */ - return "\\"; - } -#endif - if( zEnd == zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d) ){ - /* No separator, return "." as the current directory */ - *pLen = sizeof(char); - return "."; - } - if( (*pLen) == 0 ){ - *pLen = sizeof(char); -#ifdef __WINNT__ - return "\\"; -#else - return "/"; -#endif - } - return zPath; -} -/* - * Omit the vfs layer implementation from the built if the JX9_DISABLE_BUILTIN_FUNC directive is defined. - */ -#ifndef JX9_DISABLE_BUILTIN_FUNC -/* - * bool chdir(string $directory) - * Change the current directory. - * Parameters - * $directory - * The new current directory - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_chdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xChdir(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool chroot(string $directory) - * Change the root directory. - * Parameters - * $directory - * The path to change the root directory to - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_chroot(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChroot == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xChroot(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * string getcwd(void) - * Gets the current working directory. - * Parameters - * None - * Return - * Returns the current working directory on success, or FALSE on failure. - */ -static int jx9Vfs_getcwd(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int rc; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xGetcwd == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - jx9_result_string(pCtx, "", 0); - /* Perform the requested operation */ - rc = pVfs->xGetcwd(pCtx); - if( rc != JX9_OK ){ - /* Error, return FALSE */ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * bool rmdir(string $directory) - * Removes directory. - * Parameters - * $directory - * The path to the directory - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_rmdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xRmdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xRmdir(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool is_dir(string $filename) - * Tells whether the given filename is a directory. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_is_dir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xIsdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xIsdir(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool mkdir(string $pathname[, int $mode = 0777]) - * Make a directory. - * Parameters - * $pathname - * The directory path. - * $mode - * The mode is 0777 by default, which means the widest possible access. - * Note: - * mode is ignored on Windows. - * Note that you probably want to specify the mode as an octal number, which means - * it should have a leading zero. The mode is also modified by the current umask - * which you can change using umask(). - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_mkdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int iRecursive = 0; - const char *zPath; - jx9_vfs *pVfs; - int iMode, rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xMkdir == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); -#ifdef __WINNT__ - iMode = 0; -#else - /* Assume UNIX */ - iMode = 0777; -#endif - if( nArg > 1 ){ - iMode = jx9_value_to_int(apArg[1]); - if( nArg > 2 ){ - iRecursive = jx9_value_to_bool(apArg[2]); - } - } - /* Perform the requested operation */ - rc = pVfs->xMkdir(zPath, iMode, iRecursive); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool rename(string $oldname, string $newname) - * Attempts to rename oldname to newname. - * Parameters - * $oldname - * Old name. - * $newname - * New name. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_rename(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zOld, *zNew; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xRename == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - zOld = jx9_value_to_string(apArg[0], 0); - zNew = jx9_value_to_string(apArg[1], 0); - rc = pVfs->xRename(zOld, zNew); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK ); - return JX9_OK; -} -/* - * string realpath(string $path) - * Returns canonicalized absolute pathname. - * Parameters - * $path - * Target path. - * Return - * Canonicalized absolute pathname on success. or FALSE on failure. - */ -static int jx9Vfs_realpath(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xRealpath == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Set an empty string untnil the underlying OS interface change that */ - jx9_result_string(pCtx, "", 0); - /* Perform the requested operation */ - zPath = jx9_value_to_string(apArg[0], 0); - rc = pVfs->xRealpath(zPath, pCtx); - if( rc != JX9_OK ){ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * int sleep(int $seconds) - * Delays the program execution for the given number of seconds. - * Parameters - * $seconds - * Halt time in seconds. - * Return - * Zero on success or FALSE on failure. - */ -static int jx9Vfs_sleep(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int rc, nSleep; - if( nArg < 1 || !jx9_value_is_int(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xSleep == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Amount to sleep */ - nSleep = jx9_value_to_int(apArg[0]); - if( nSleep < 0 ){ - /* Invalid value, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation (Microseconds) */ - rc = pVfs->xSleep((unsigned int)(nSleep * SX_USEC_PER_SEC)); - if( rc != JX9_OK ){ - /* Return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return zero */ - jx9_result_int(pCtx, 0); - } - return JX9_OK; -} -/* - * void usleep(int $micro_seconds) - * Delays program execution for the given number of micro seconds. - * Parameters - * $micro_seconds - * Halt time in micro seconds. A micro second is one millionth of a second. - * Return - * None. - */ -static int jx9Vfs_usleep(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int nSleep; - if( nArg < 1 || !jx9_value_is_int(apArg[0]) ){ - /* Missing/Invalid argument, return immediately */ - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xSleep == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - return JX9_OK; - } - /* Amount to sleep */ - nSleep = jx9_value_to_int(apArg[0]); - if( nSleep < 0 ){ - /* Invalid value, return immediately */ - return JX9_OK; - } - /* Perform the requested operation (Microseconds) */ - pVfs->xSleep((unsigned int)nSleep); - return JX9_OK; -} -/* - * bool unlink (string $filename) - * Delete a file. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_unlink(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUnlink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xUnlink(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool chmod(string $filename, int $mode) - * Attempts to change the mode of the specified file to that given in mode. - * Parameters - * $filename - * Path to the file. - * $mode - * Mode (Must be an integer) - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_chmod(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int iMode; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChmod == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Extract the mode */ - iMode = jx9_value_to_int(apArg[1]); - /* Perform the requested operation */ - rc = pVfs->xChmod(zPath, iMode); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool chown(string $filename, string $user) - * Attempts to change the owner of the file filename to user user. - * Parameters - * $filename - * Path to the file. - * $user - * Username. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_chown(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zUser; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChown == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Extract the user */ - zUser = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xChown(zPath, zUser); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool chgrp(string $filename, string $group) - * Attempts to change the group of the file filename to group. - * Parameters - * $filename - * Path to the file. - * $group - * groupname. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_chgrp(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zGroup; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xChgrp == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Extract the user */ - zGroup = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xChgrp(zPath, zGroup); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * int64 disk_free_space(string $directory) - * Returns available space on filesystem or disk partition. - * Parameters - * $directory - * A directory of the filesystem or disk partition. - * Return - * Returns the number of available bytes as a 64-bit integer or FALSE on failure. - */ -static int jx9Vfs_disk_free_space(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iSize; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFreeSpace == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iSize = pVfs->xFreeSpace(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iSize); - return JX9_OK; -} -/* - * int64 disk_total_space(string $directory) - * Returns the total size of a filesystem or disk partition. - * Parameters - * $directory - * A directory of the filesystem or disk partition. - * Return - * Returns the number of available bytes as a 64-bit integer or FALSE on failure. - */ -static int jx9Vfs_disk_total_space(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iSize; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xTotalSpace == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iSize = pVfs->xTotalSpace(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iSize); - return JX9_OK; -} -/* - * bool file_exists(string $filename) - * Checks whether a file or directory exists. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_file_exists(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileExists == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xFileExists(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * int64 file_size(string $filename) - * Gets the size for the given file. - * Parameters - * $filename - * Path to the file. - * Return - * File size on success or FALSE on failure. - */ -static int jx9Vfs_file_size(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iSize; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileSize == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iSize = pVfs->xFileSize(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iSize); - return JX9_OK; -} -/* - * int64 fileatime(string $filename) - * Gets the last access time of the given file. - * Parameters - * $filename - * Path to the file. - * Return - * File atime on success or FALSE on failure. - */ -static int jx9Vfs_file_atime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iTime; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileAtime == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iTime = pVfs->xFileAtime(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iTime); - return JX9_OK; -} -/* - * int64 filemtime(string $filename) - * Gets file modification time. - * Parameters - * $filename - * Path to the file. - * Return - * File mtime on success or FALSE on failure. - */ -static int jx9Vfs_file_mtime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iTime; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileMtime == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iTime = pVfs->xFileMtime(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iTime); - return JX9_OK; -} -/* - * int64 filectime(string $filename) - * Gets inode change time of file. - * Parameters - * $filename - * Path to the file. - * Return - * File ctime on success or FALSE on failure. - */ -static int jx9Vfs_file_ctime(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_int64 iTime; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFileCtime == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - iTime = pVfs->xFileCtime(zPath); - /* IO return value */ - jx9_result_int64(pCtx, iTime); - return JX9_OK; -} -/* - * bool is_file(string $filename) - * Tells whether the filename is a regular file. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_is_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xIsfile == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xIsfile(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool is_link(string $filename) - * Tells whether the filename is a symbolic link. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_is_link(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xIslink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xIslink(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool is_readable(string $filename) - * Tells whether a file exists and is readable. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_is_readable(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xReadable == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xReadable(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool is_writable(string $filename) - * Tells whether the filename is writable. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_is_writable(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xWritable == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xWritable(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool is_executable(string $filename) - * Tells whether the filename is executable. - * Parameters - * $filename - * Path to the file. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_is_executable(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xExecutable == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xExecutable(zPath); - /* IO return value */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * string filetype(string $filename) - * Gets file type. - * Parameters - * $filename - * Path to the file. - * Return - * The type of the file. Possible values are fifo, char, dir, block, link - * file, socket and unknown. - */ -static int jx9Vfs_filetype(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - jx9_vfs *pVfs; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xFiletype == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the desired directory */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Set the empty string as the default return value */ - jx9_result_string(pCtx, "", 0); - /* Perform the requested operation */ - pVfs->xFiletype(zPath, pCtx); - return JX9_OK; -} -/* - * array stat(string $filename) - * Gives information about a file. - * Parameters - * $filename - * Path to the file. - * Return - * An associative array on success holding the following entries on success - * 0 dev device number - * 1 ino inode number (zero on windows) - * 2 mode inode protection mode - * 3 nlink number of links - * 4 uid userid of owner (zero on windows) - * 5 gid groupid of owner (zero on windows) - * 6 rdev device type, if inode device - * 7 size size in bytes - * 8 atime time of last access (Unix timestamp) - * 9 mtime time of last modification (Unix timestamp) - * 10 ctime time of last inode change (Unix timestamp) - * 11 blksize blocksize of filesystem IO (zero on windows) - * 12 blocks number of 512-byte blocks allocated. - * Note: - * FALSE is returned on failure. - */ -static int jx9Vfs_stat(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue; - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xStat == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xStat(zPath, pArray, pValue); - if( rc != JX9_OK ){ - /* IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the associative array */ - jx9_result_value(pCtx, pArray); - } - /* Don't worry about freeing memory here, everything will be released - * automatically as soon we return from this function. */ - return JX9_OK; -} -/* - * array lstat(string $filename) - * Gives information about a file or symbolic link. - * Parameters - * $filename - * Path to the file. - * Return - * An associative array on success holding the following entries on success - * 0 dev device number - * 1 ino inode number (zero on windows) - * 2 mode inode protection mode - * 3 nlink number of links - * 4 uid userid of owner (zero on windows) - * 5 gid groupid of owner (zero on windows) - * 6 rdev device type, if inode device - * 7 size size in bytes - * 8 atime time of last access (Unix timestamp) - * 9 mtime time of last modification (Unix timestamp) - * 10 ctime time of last inode change (Unix timestamp) - * 11 blksize blocksize of filesystem IO (zero on windows) - * 12 blocks number of 512-byte blocks allocated. - * Note: - * FALSE is returned on failure. - */ -static int jx9Vfs_lstat(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue; - const char *zPath; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xlStat == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zPath = jx9_value_to_string(apArg[0], 0); - /* Perform the requested operation */ - rc = pVfs->xlStat(zPath, pArray, pValue); - if( rc != JX9_OK ){ - /* IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the associative array */ - jx9_result_value(pCtx, pArray); - } - /* Don't worry about freeing memory here, everything will be released - * automatically as soon we return from this function. */ - return JX9_OK; -} -/* - * string getenv(string $varname) - * Gets the value of an environment variable. - * Parameters - * $varname - * The variable name. - * Return - * Returns the value of the environment variable varname, or FALSE if the environment - * variable varname does not exist. - */ -static int jx9Vfs_getenv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zEnv; - jx9_vfs *pVfs; - int iLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xGetenv == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the environment variable */ - zEnv = jx9_value_to_string(apArg[0], &iLen); - /* Set a boolean FALSE as the default return value */ - jx9_result_bool(pCtx, 0); - if( iLen < 1 ){ - /* Empty string */ - return JX9_OK; - } - /* Perform the requested operation */ - pVfs->xGetenv(zEnv, pCtx); - return JX9_OK; -} -/* - * bool putenv(string $settings) - * Set the value of an environment variable. - * Parameters - * $setting - * The setting, like "FOO=BAR" - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_putenv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zName, *zValue; - char *zSettings, *zEnd; - jx9_vfs *pVfs; - int iLen, rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the setting variable */ - zSettings = (char *)jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Empty string, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Parse the setting */ - zEnd = &zSettings[iLen]; - zValue = 0; - zName = zSettings; - while( zSettings < zEnd ){ - if( zSettings[0] == '=' ){ - /* Null terminate the name */ - zSettings[0] = 0; - zValue = &zSettings[1]; - break; - } - zSettings++; - } - /* Install the environment variable in the $_Env array */ - if( zValue == 0 || zName[0] == 0 || zValue >= zEnd || zName >= zValue ){ - /* Invalid settings, retun FALSE */ - jx9_result_bool(pCtx, 0); - if( zSettings < zEnd ){ - zSettings[0] = '='; - } - return JX9_OK; - } - jx9_vm_config(pCtx->pVm, JX9_VM_CONFIG_ENV_ATTR, zName, zValue, (int)(zEnd-zValue)); - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xSetenv == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - zSettings[0] = '='; - return JX9_OK; - } - /* Perform the requested operation */ - rc = pVfs->xSetenv(zName, zValue); - jx9_result_bool(pCtx, rc == JX9_OK ); - zSettings[0] = '='; - return JX9_OK; -} -/* - * bool touch(string $filename[, int64 $time = time()[, int64 $atime]]) - * Sets access and modification time of file. - * Note: On windows - * If the file does not exists, it will not be created. - * Parameters - * $filename - * The name of the file being touched. - * $time - * The touch time. If time is not supplied, the current system time is used. - * $atime - * If present, the access time of the given filename is set to the value of atime. - * Otherwise, it is set to the value passed to the time parameter. If neither are - * present, the current system time is used. - * Return - * TRUE on success or FALSE on failure. -*/ -static int jx9Vfs_touch(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_int64 nTime, nAccess; - const char *zFile; - jx9_vfs *pVfs; - int rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xTouch == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - nTime = nAccess = -1; - zFile = jx9_value_to_string(apArg[0], 0); - if( nArg > 1 ){ - nTime = jx9_value_to_int64(apArg[1]); - if( nArg > 2 ){ - nAccess = jx9_value_to_int64(apArg[1]); - }else{ - nAccess = nTime; - } - } - rc = pVfs->xTouch(zFile, nTime, nAccess); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * Path processing functions that do not need access to the VFS layer - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * string dirname(string $path) - * Returns parent directory's path. - * Parameters - * $path - * Target path. - * On Windows, both slash (/) and backslash (\) are used as directory separator character. - * In other environments, it is the forward slash (/). - * Return - * The path of the parent directory. If there are no slashes in path, a dot ('.') - * is returned, indicating the current directory. - */ -static int jx9Builtin_dirname(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zDir; - int iLen, iDirlen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Point to the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Reuturn "." */ - jx9_result_string(pCtx, ".", sizeof(char)); - return JX9_OK; - } - /* Perform the requested operation */ - zDir = jx9ExtractDirName(zPath, iLen, &iDirlen); - /* Return directory name */ - jx9_result_string(pCtx, zDir, iDirlen); - return JX9_OK; -} -/* - * string basename(string $path[, string $suffix ]) - * Returns trailing name component of path. - * Parameters - * $path - * Target path. - * On Windows, both slash (/) and backslash (\) are used as directory separator character. - * In other environments, it is the forward slash (/). - * $suffix - * If the name component ends in suffix this will also be cut off. - * Return - * The base name of the given path. - */ -static int jx9Builtin_basename(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath, *zBase, *zEnd; - int c, d, iLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - c = d = '/'; -#ifdef __WINNT__ - d = '\\'; -#endif - /* Point to the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Perform the requested operation */ - zEnd = &zPath[iLen - 1]; - /* Ignore trailing '/' */ - while( zEnd > zPath && ( (int)zEnd[0] == c || (int)zEnd[0] == d ) ){ - zEnd--; - } - iLen = (int)(&zEnd[1]-zPath); - while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){ - zEnd--; - } - zBase = (zEnd > zPath) ? &zEnd[1] : zPath; - zEnd = &zPath[iLen]; - if( nArg > 1 && jx9_value_is_string(apArg[1]) ){ - const char *zSuffix; - int nSuffix; - /* Strip suffix */ - zSuffix = jx9_value_to_string(apArg[1], &nSuffix); - if( nSuffix > 0 && nSuffix < iLen && SyMemcmp(&zEnd[-nSuffix], zSuffix, nSuffix) == 0 ){ - zEnd -= nSuffix; - } - } - /* Store the basename */ - jx9_result_string(pCtx, zBase, (int)(zEnd-zBase)); - return JX9_OK; -} -/* - * value pathinfo(string $path [, int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ]) - * Returns information about a file path. - * Parameter - * $path - * The path to be parsed. - * $options - * If present, specifies a specific element to be returned; one of - * PATHINFO_DIRNAME, PATHINFO_BASENAME, PATHINFO_EXTENSION or PATHINFO_FILENAME. - * Return - * If the options parameter is not passed, an associative array containing the following - * elements is returned: dirname, basename, extension (if any), and filename. - * If options is present, returns a string containing the requested element. - */ -typedef struct path_info path_info; -struct path_info -{ - SyString sDir; /* Directory [i.e: /var/www] */ - SyString sBasename; /* Basename [i.e httpd.conf] */ - SyString sExtension; /* File extension [i.e xml, pdf..] */ - SyString sFilename; /* Filename */ -}; -/* - * Extract path fields. - */ -static sxi32 ExtractPathInfo(const char *zPath, int nByte, path_info *pOut) -{ - const char *zPtr, *zEnd = &zPath[nByte - 1]; - SyString *pCur; - int c, d; - c = d = '/'; -#ifdef __WINNT__ - d = '\\'; -#endif - /* Zero the structure */ - SyZero(pOut, sizeof(path_info)); - /* Handle special case */ - if( nByte == sizeof(char) && ( (int)zPath[0] == c || (int)zPath[0] == d ) ){ -#ifdef __WINNT__ - SyStringInitFromBuf(&pOut->sDir, "\\", sizeof(char)); -#else - SyStringInitFromBuf(&pOut->sDir, "/", sizeof(char)); -#endif - return SXRET_OK; - } - /* Extract the basename */ - while( zEnd > zPath && ( (int)zEnd[0] != c && (int)zEnd[0] != d ) ){ - zEnd--; - } - zPtr = (zEnd > zPath) ? &zEnd[1] : zPath; - zEnd = &zPath[nByte]; - /* dirname */ - pCur = &pOut->sDir; - SyStringInitFromBuf(pCur, zPath, zPtr-zPath); - if( pCur->nByte > 1 ){ - SyStringTrimTrailingChar(pCur, '/'); -#ifdef __WINNT__ - SyStringTrimTrailingChar(pCur, '\\'); -#endif - }else if( (int)zPath[0] == c || (int)zPath[0] == d ){ -#ifdef __WINNT__ - SyStringInitFromBuf(&pOut->sDir, "\\", sizeof(char)); -#else - SyStringInitFromBuf(&pOut->sDir, "/", sizeof(char)); -#endif - } - /* basename/filename */ - pCur = &pOut->sBasename; - SyStringInitFromBuf(pCur, zPtr, zEnd-zPtr); - SyStringTrimLeadingChar(pCur, '/'); -#ifdef __WINNT__ - SyStringTrimLeadingChar(pCur, '\\'); -#endif - SyStringDupPtr(&pOut->sFilename, pCur); - if( pCur->nByte > 0 ){ - /* extension */ - zEnd--; - while( zEnd > pCur->zString /*basename*/ && zEnd[0] != '.' ){ - zEnd--; - } - if( zEnd > pCur->zString ){ - zEnd++; /* Jump leading dot */ - SyStringInitFromBuf(&pOut->sExtension, zEnd, &zPath[nByte]-zEnd); - /* Fix filename */ - pCur = &pOut->sFilename; - if( pCur->nByte > SyStringLength(&pOut->sExtension) ){ - pCur->nByte -= 1 + SyStringLength(&pOut->sExtension); - } - } - } - return SXRET_OK; -} -/* - * value pathinfo(string $path [, int $options = PATHINFO_DIRNAME | PATHINFO_BASENAME | PATHINFO_EXTENSION | PATHINFO_FILENAME ]) - * See block comment above. - */ -static int jx9Builtin_pathinfo(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zPath; - path_info sInfo; - SyString *pComp; - int iLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid argument, return the empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Point to the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - if( iLen < 1 ){ - /* Empty string */ - jx9_result_string(pCtx, "", 0); - return JX9_OK; - } - /* Extract path info */ - ExtractPathInfo(zPath, iLen, &sInfo); - if( nArg > 1 && jx9_value_is_int(apArg[1]) ){ - /* Return path component */ - int nComp = jx9_value_to_int(apArg[1]); - switch(nComp){ - case 1: /* PATHINFO_DIRNAME */ - pComp = &sInfo.sDir; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - case 2: /*PATHINFO_BASENAME*/ - pComp = &sInfo.sBasename; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - case 3: /*PATHINFO_EXTENSION*/ - pComp = &sInfo.sExtension; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - case 4: /*PATHINFO_FILENAME*/ - pComp = &sInfo.sFilename; - if( pComp->nByte > 0 ){ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - }else{ - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - } - break; - default: - /* Expand the empty string */ - jx9_result_string(pCtx, "", 0); - break; - } - }else{ - /* Return an associative array */ - jx9_value *pArray, *pValue; - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - /* Out of mem, return NULL */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* dirname */ - pComp = &sInfo.sDir; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "dirname", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - /* basername */ - pComp = &sInfo.sBasename; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "basename", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - /* extension */ - pComp = &sInfo.sExtension; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "extension", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - /* filename */ - pComp = &sInfo.sFilename; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - /* Perform the insertion */ - jx9_array_add_strkey_elem(pArray, "filename", pValue); /* Will make it's own copy */ - } - /* Return the created array */ - jx9_result_value(pCtx, pArray); - /* Don't worry about freeing memory, everything will be released - * automatically as soon we return from this foreign function. - */ - } - return JX9_OK; -} -/* - * Globbing implementation extracted from the sqlite3 source tree. - * Original author: D. Richard Hipp (http://www.sqlite.org) - * Status: Public Domain - */ -typedef unsigned char u8; -/* An array to map all upper-case characters into their corresponding -** lower-case character. -** -** SQLite only considers US-ASCII (or EBCDIC) characters. We do not -** handle case conversions for the UTF character set since the tables -** involved are nearly as big or bigger than SQLite itself. -*/ -static const unsigned char sqlite3UpperToLower[] = { - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, - 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, - 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, - 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 97, 98, 99, 100, 101, 102, 103, - 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, - 122, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, - 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, - 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, - 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159, 160, 161, - 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175, 176, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, - 198, 199, 200, 201, 202, 203, 204, 205, 206, 207, 208, 209, 210, 211, 212, 213, 214, 215, - 216, 217, 218, 219, 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, - 234, 235, 236, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, - 252, 253, 254, 255 -}; -#define GlogUpperToLower(A) if( A<0x80 ){ A = sqlite3UpperToLower[A]; } -/* -** Assuming zIn points to the first byte of a UTF-8 character, -** advance zIn to point to the first byte of the next UTF-8 character. -*/ -#define SQLITE_SKIP_UTF8(zIn) { \ - if( (*(zIn++))>=0xc0 ){ \ - while( (*zIn & 0xc0)==0x80 ){ zIn++; } \ - } \ -} -/* -** Compare two UTF-8 strings for equality where the first string can -** potentially be a "glob" expression. Return true (1) if they -** are the same and false (0) if they are different. -** -** Globbing rules: -** -** '*' Matches any sequence of zero or more characters. -** -** '?' Matches exactly one character. -** -** [...] Matches one character from the enclosed list of -** characters. -** -** [^...] Matches one character not in the enclosed list. -** -** With the [...] and [^...] matching, a ']' character can be included -** in the list by making it the first character after '[' or '^'. A -** range of characters can be specified using '-'. Example: -** "[a-z]" matches any single lower-case letter. To match a '-', make -** it the last character in the list. -** -** This routine is usually quick, but can be N**2 in the worst case. -** -** Hints: to match '*' or '?', put them in "[]". Like this: -** -** abc[*]xyz Matches "abc*xyz" only -*/ -static int patternCompare( - const u8 *zPattern, /* The glob pattern */ - const u8 *zString, /* The string to compare against the glob */ - const int esc, /* The escape character */ - int noCase -){ - int c, c2; - int invert; - int seen; - u8 matchOne = '?'; - u8 matchAll = '*'; - u8 matchSet = '['; - int prevEscape = 0; /* True if the previous character was 'escape' */ - - if( !zPattern || !zString ) return 0; - while( (c = jx9Utf8Read(zPattern, 0, &zPattern))!=0 ){ - if( !prevEscape && c==matchAll ){ - while( (c= jx9Utf8Read(zPattern, 0, &zPattern)) == matchAll - || c == matchOne ){ - if( c==matchOne && jx9Utf8Read(zString, 0, &zString)==0 ){ - return 0; - } - } - if( c==0 ){ - return 1; - }else if( c==esc ){ - c = jx9Utf8Read(zPattern, 0, &zPattern); - if( c==0 ){ - return 0; - } - }else if( c==matchSet ){ - if( (esc==0) || (matchSet<0x80) ) return 0; - while( *zString && patternCompare(&zPattern[-1], zString, esc, noCase)==0 ){ - SQLITE_SKIP_UTF8(zString); - } - return *zString!=0; - } - while( (c2 = jx9Utf8Read(zString, 0, &zString))!=0 ){ - if( noCase ){ - GlogUpperToLower(c2); - GlogUpperToLower(c); - while( c2 != 0 && c2 != c ){ - c2 = jx9Utf8Read(zString, 0, &zString); - GlogUpperToLower(c2); - } - }else{ - while( c2 != 0 && c2 != c ){ - c2 = jx9Utf8Read(zString, 0, &zString); - } - } - if( c2==0 ) return 0; - if( patternCompare(zPattern, zString, esc, noCase) ) return 1; - } - return 0; - }else if( !prevEscape && c==matchOne ){ - if( jx9Utf8Read(zString, 0, &zString)==0 ){ - return 0; - } - }else if( c==matchSet ){ - int prior_c = 0; - if( esc == 0 ) return 0; - seen = 0; - invert = 0; - c = jx9Utf8Read(zString, 0, &zString); - if( c==0 ) return 0; - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - if( c2=='^' ){ - invert = 1; - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - } - if( c2==']' ){ - if( c==']' ) seen = 1; - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - } - while( c2 && c2!=']' ){ - if( c2=='-' && zPattern[0]!=']' && zPattern[0]!=0 && prior_c>0 ){ - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - if( c>=prior_c && c<=c2 ) seen = 1; - prior_c = 0; - }else{ - if( c==c2 ){ - seen = 1; - } - prior_c = c2; - } - c2 = jx9Utf8Read(zPattern, 0, &zPattern); - } - if( c2==0 || (seen ^ invert)==0 ){ - return 0; - } - }else if( esc==c && !prevEscape ){ - prevEscape = 1; - }else{ - c2 = jx9Utf8Read(zString, 0, &zString); - if( noCase ){ - GlogUpperToLower(c); - GlogUpperToLower(c2); - } - if( c!=c2 ){ - return 0; - } - prevEscape = 0; - } - } - return *zString==0; -} -/* - * Wrapper around patternCompare() defined above. - * See block comment above for more information. - */ -static int Glob(const unsigned char *zPattern, const unsigned char *zString, int iEsc, int CaseCompare) -{ - int rc; - if( iEsc < 0 ){ - iEsc = '\\'; - } - rc = patternCompare(zPattern, zString, iEsc, CaseCompare); - return rc; -} -/* - * bool fnmatch(string $pattern, string $string[, int $flags = 0 ]) - * Match filename against a pattern. - * Parameters - * $pattern - * The shell wildcard pattern. - * $string - * The tested string. - * $flags - * A list of possible flags: - * FNM_NOESCAPE Disable backslash escaping. - * FNM_PATHNAME Slash in string only matches slash in the given pattern. - * FNM_PERIOD Leading period in string must be exactly matched by period in the given pattern. - * FNM_CASEFOLD Caseless match. - * Return - * TRUE if there is a match, FALSE otherwise. - */ -static int jx9Builtin_fnmatch(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zPattern; - int iEsc = '\\'; - int noCase = 0; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the pattern and the string */ - zPattern = jx9_value_to_string(apArg[0], 0); - zString = jx9_value_to_string(apArg[1], 0); - /* Extract the flags if avaialble */ - if( nArg > 2 && jx9_value_is_int(apArg[2]) ){ - rc = jx9_value_to_int(apArg[2]); - if( rc & 0x01 /*FNM_NOESCAPE*/){ - iEsc = 0; - } - if( rc & 0x08 /*FNM_CASEFOLD*/){ - noCase = 1; - } - } - /* Go globbing */ - rc = Glob((const unsigned char *)zPattern, (const unsigned char *)zString, iEsc, noCase); - /* Globbing result */ - jx9_result_bool(pCtx, rc); - return JX9_OK; -} -/* - * bool strglob(string $pattern, string $string) - * Match string against a pattern. - * Parameters - * $pattern - * The shell wildcard pattern. - * $string - * The tested string. - * Return - * TRUE if there is a match, FALSE otherwise. - */ -static int jx9Builtin_strglob(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zString, *zPattern; - int iEsc = '\\'; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the pattern and the string */ - zPattern = jx9_value_to_string(apArg[0], 0); - zString = jx9_value_to_string(apArg[1], 0); - /* Go globbing */ - rc = Glob((const unsigned char *)zPattern, (const unsigned char *)zString, iEsc, 0); - /* Globbing result */ - jx9_result_bool(pCtx, rc); - return JX9_OK; -} -/* - * bool link(string $target, string $link) - * Create a hard link. - * Parameters - * $target - * Target of the link. - * $link - * The link name. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_link(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zTarget, *zLink; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xLink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the given arguments */ - zTarget = jx9_value_to_string(apArg[0], 0); - zLink = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xLink(zTarget, zLink, 0/*Not a symbolic link */); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK ); - return JX9_OK; -} -/* - * bool symlink(string $target, string $link) - * Creates a symbolic link. - * Parameters - * $target - * Target of the link. - * $link - * The link name. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Vfs_symlink(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zTarget, *zLink; - jx9_vfs *pVfs; - int rc; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xLink == 0 ){ - /* IO routine not implemented, return NULL */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS, JX9 is returning FALSE", - jx9_function_name(pCtx) - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the given arguments */ - zTarget = jx9_value_to_string(apArg[0], 0); - zLink = jx9_value_to_string(apArg[1], 0); - /* Perform the requested operation */ - rc = pVfs->xLink(zTarget, zLink, 1/*A symbolic link */); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK ); - return JX9_OK; -} -/* - * int umask([ int $mask ]) - * Changes the current umask. - * Parameters - * $mask - * The new umask. - * Return - * umask() without arguments simply returns the current umask. - * Otherwise the old umask is returned. - */ -static int jx9Vfs_umask(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int iOld, iNew; - jx9_vfs *pVfs; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUmask == 0 ){ - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - iNew = 0; - if( nArg > 0 ){ - iNew = jx9_value_to_int(apArg[0]); - } - /* Perform the requested operation */ - iOld = pVfs->xUmask(iNew); - /* Old mask */ - jx9_result_int(pCtx, iOld); - return JX9_OK; -} -/* - * string sys_get_temp_dir() - * Returns directory path used for temporary files. - * Parameters - * None - * Return - * Returns the path of the temporary directory. - */ -static int jx9Vfs_sys_get_temp_dir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - /* Set the empty string as the default return value */ - jx9_result_string(pCtx, "", 0); - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xTempDir == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return "" */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - return JX9_OK; - } - /* Perform the requested operation */ - pVfs->xTempDir(pCtx); - return JX9_OK; -} -/* - * string get_current_user() - * Returns the name of the current working user. - * Parameters - * None - * Return - * Returns the name of the current working user. - */ -static int jx9Vfs_get_current_user(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUsername == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - /* Set a dummy username */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return JX9_OK; - } - /* Perform the requested operation */ - pVfs->xUsername(pCtx); - return JX9_OK; -} -/* - * int64 getmypid() - * Gets process ID. - * Parameters - * None - * Return - * Returns the process ID. - */ -static int jx9Vfs_getmypid(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_int64 nProcessId; - jx9_vfs *pVfs; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xProcessId == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the requested operation */ - nProcessId = (jx9_int64)pVfs->xProcessId(); - /* Set the result */ - jx9_result_int64(pCtx, nProcessId); - return JX9_OK; -} -/* - * int getmyuid() - * Get user ID. - * Parameters - * None - * Return - * Returns the user ID. - */ -static int jx9Vfs_getmyuid(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int nUid; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xUid == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the requested operation */ - nUid = pVfs->xUid(); - /* Set the result */ - jx9_result_int(pCtx, nUid); - return JX9_OK; -} -/* - * int getmygid() - * Get group ID. - * Parameters - * None - * Return - * Returns the group ID. - */ -static int jx9Vfs_getmygid(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vfs *pVfs; - int nGid; - /* Point to the underlying vfs */ - pVfs = (jx9_vfs *)jx9_context_user_data(pCtx); - if( pVfs == 0 || pVfs->xGid == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* IO routine not implemented, return -1 */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying VFS", - jx9_function_name(pCtx) - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Perform the requested operation */ - nGid = pVfs->xGid(); - /* Set the result */ - jx9_result_int(pCtx, nGid); - return JX9_OK; -} -#ifdef __WINNT__ -#include -#elif defined(__UNIXES__) -#include -#endif -/* - * string uname([ string $mode = "a" ]) - * Returns information about the host operating system. - * Parameters - * $mode - * mode is a single character that defines what information is returned: - * 'a': This is the default. Contains all modes in the sequence "s n r v m". - * 's': Operating system name. eg. FreeBSD. - * 'n': Host name. eg. localhost.example.com. - * 'r': Release name. eg. 5.1.2-RELEASE. - * 'v': Version information. Varies a lot between operating systems. - * 'm': Machine type. eg. i386. - * Return - * OS description as a string. - */ -static int jx9Vfs_uname(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ -#if defined(__WINNT__) - const char *zName = "Microsoft Windows"; - OSVERSIONINFOW sVer; -#elif defined(__UNIXES__) - struct utsname sName; -#endif - const char *zMode = "a"; - if( nArg > 0 && jx9_value_is_string(apArg[0]) ){ - /* Extract the desired mode */ - zMode = jx9_value_to_string(apArg[0], 0); - } -#if defined(__WINNT__) - sVer.dwOSVersionInfoSize = sizeof(sVer); - if( TRUE != GetVersionExW(&sVer)){ - jx9_result_string(pCtx, zName, -1); - return JX9_OK; - } - if( sVer.dwPlatformId == VER_PLATFORM_WIN32_NT ){ - if( sVer.dwMajorVersion <= 4 ){ - zName = "Microsoft Windows NT"; - }else if( sVer.dwMajorVersion == 5 ){ - switch(sVer.dwMinorVersion){ - case 0: zName = "Microsoft Windows 2000"; break; - case 1: zName = "Microsoft Windows XP"; break; - case 2: zName = "Microsoft Windows Server 2003"; break; - } - }else if( sVer.dwMajorVersion == 6){ - switch(sVer.dwMinorVersion){ - case 0: zName = "Microsoft Windows Vista"; break; - case 1: zName = "Microsoft Windows 7"; break; - case 2: zName = "Microsoft Windows 8"; break; - default: break; - } - } - } - switch(zMode[0]){ - case 's': - /* Operating system name */ - jx9_result_string(pCtx, zName, -1/* Compute length automatically*/); - break; - case 'n': - /* Host name */ - jx9_result_string(pCtx, "localhost", (int)sizeof("localhost")-1); - break; - case 'r': - case 'v': - /* Version information. */ - jx9_result_string_format(pCtx, "%u.%u build %u", - sVer.dwMajorVersion, sVer.dwMinorVersion, sVer.dwBuildNumber - ); - break; - case 'm': - /* Machine name */ - jx9_result_string(pCtx, "x86", (int)sizeof("x86")-1); - break; - default: - jx9_result_string_format(pCtx, "%s localhost %u.%u build %u x86", - zName, - sVer.dwMajorVersion, sVer.dwMinorVersion, sVer.dwBuildNumber - ); - break; - } -#elif defined(__UNIXES__) - if( uname(&sName) != 0 ){ - jx9_result_string(pCtx, "Unix", (int)sizeof("Unix")-1); - return JX9_OK; - } - switch(zMode[0]){ - case 's': - /* Operating system name */ - jx9_result_string(pCtx, sName.sysname, -1/* Compute length automatically*/); - break; - case 'n': - /* Host name */ - jx9_result_string(pCtx, sName.nodename, -1/* Compute length automatically*/); - break; - case 'r': - /* Release information */ - jx9_result_string(pCtx, sName.release, -1/* Compute length automatically*/); - break; - case 'v': - /* Version information. */ - jx9_result_string(pCtx, sName.version, -1/* Compute length automatically*/); - break; - case 'm': - /* Machine name */ - jx9_result_string(pCtx, sName.machine, -1/* Compute length automatically*/); - break; - default: - jx9_result_string_format(pCtx, - "%s %s %s %s %s", - sName.sysname, - sName.release, - sName.version, - sName.nodename, - sName.machine - ); - break; - } -#else - jx9_result_string(pCtx, "Host Operating System/localhost", (int)sizeof("Host Operating System/localhost")-1); -#endif - return JX9_OK; -} -/* - * Section: - * IO stream implementation. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -typedef struct io_private io_private; -struct io_private -{ - const jx9_io_stream *pStream; /* Underlying IO device */ - void *pHandle; /* IO handle */ - /* Unbuffered IO */ - SyBlob sBuffer; /* Working buffer */ - sxu32 nOfft; /* Current read offset */ - sxu32 iMagic; /* Sanity check to avoid misuse */ -}; -#define IO_PRIVATE_MAGIC 0xFEAC14 -/* Make sure we are dealing with a valid io_private instance */ -#define IO_PRIVATE_INVALID(IO) ( IO == 0 || IO->iMagic != IO_PRIVATE_MAGIC ) -/* Forward declaration */ -static void ResetIOPrivate(io_private *pDev); -/* - * bool ftruncate(resource $handle, int64 $size) - * Truncates a file to a given length. - * Parameters - * $handle - * The file pointer. - * Note: - * The handle must be open for writing. - * $size - * The size to truncate to. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Builtin_ftruncate(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xTrunc == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - rc = pStream->xTrunc(pDev->pHandle, jx9_value_to_int64(apArg[1])); - if( rc == JX9_OK ){ - /* Discard buffered data */ - ResetIOPrivate(pDev); - } - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * int fseek(resource $handle, int $offset[, int $whence = SEEK_SET ]) - * Seeks on a file pointer. - * Parameters - * $handle - * A file system pointer resource that is typically created using fopen(). - * $offset - * The offset. - * To move to a position before the end-of-file, you need to pass a negative - * value in offset and set whence to SEEK_END. - * whence - * whence values are: - * SEEK_SET - Set position equal to offset bytes. - * SEEK_CUR - Set position to current location plus offset. - * SEEK_END - Set position to end-of-file plus offset. - * Return - * 0 on success, -1 on failure - */ -static int jx9Builtin_fseek(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 iOfft; - int whence; - int rc; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xSeek == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_int(pCtx, -1); - return JX9_OK; - } - /* Extract the offset */ - iOfft = jx9_value_to_int64(apArg[1]); - whence = 0;/* SEEK_SET */ - if( nArg > 2 && jx9_value_is_int(apArg[2]) ){ - whence = jx9_value_to_int(apArg[2]); - } - /* Perform the requested operation */ - rc = pStream->xSeek(pDev->pHandle, iOfft, whence); - if( rc == JX9_OK ){ - /* Ignore buffered data */ - ResetIOPrivate(pDev); - } - /* IO result */ - jx9_result_int(pCtx, rc == JX9_OK ? 0 : - 1); - return JX9_OK; -} -/* - * int64 ftell(resource $handle) - * Returns the current position of the file read/write pointer. - * Parameters - * $handle - * The file pointer. - * Return - * Returns the position of the file pointer referenced by handle - * as an integer; i.e., its offset into the file stream. - * FALSE is returned on failure. - */ -static int jx9Builtin_ftell(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 iOfft; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xTell == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - iOfft = pStream->xTell(pDev->pHandle); - /* IO result */ - jx9_result_int64(pCtx, iOfft); - return JX9_OK; -} -/* - * bool rewind(resource $handle) - * Rewind the position of a file pointer. - * Parameters - * $handle - * The file pointer. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Builtin_rewind(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xSeek == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - rc = pStream->xSeek(pDev->pHandle, 0, 0/*SEEK_SET*/); - if( rc == JX9_OK ){ - /* Ignore buffered data */ - ResetIOPrivate(pDev); - } - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool fflush(resource $handle) - * Flushes the output to a file. - * Parameters - * $handle - * The file pointer. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Builtin_fflush(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xSync == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - rc = pStream->xSync(pDev->pHandle); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * bool feof(resource $handle) - * Tests for end-of-file on a file pointer. - * Parameters - * $handle - * The file pointer. - * Return - * Returns TRUE if the file pointer is at EOF.FALSE otherwise - */ -static int jx9Builtin_feof(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 1); - return JX9_OK; - } - rc = SXERR_EOF; - /* Perform the requested operation */ - if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){ - /* Data is available */ - rc = JX9_OK; - }else{ - char zBuf[4096]; - jx9_int64 n; - /* Perform a buffered read */ - n = pStream->xRead(pDev->pHandle, zBuf, sizeof(zBuf)); - if( n > 0 ){ - /* Copy buffered data */ - SyBlobAppend(&pDev->sBuffer, zBuf, (sxu32)n); - rc = JX9_OK; - } - } - /* EOF or not */ - jx9_result_bool(pCtx, rc == SXERR_EOF); - return JX9_OK; -} -/* - * Read n bytes from the underlying IO stream device. - * Return total numbers of bytes readen on success. A number < 1 on failure - * [i.e: IO error ] or EOF. - */ -static jx9_int64 StreamRead(io_private *pDev, void *pBuf, jx9_int64 nLen) -{ - const jx9_io_stream *pStream = pDev->pStream; - char *zBuf = (char *)pBuf; - jx9_int64 n, nRead; - n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft; - if( n > 0 ){ - if( n > nLen ){ - n = nLen; - } - /* Copy the buffered data */ - SyMemcpy(SyBlobDataAt(&pDev->sBuffer, pDev->nOfft), pBuf, (sxu32)n); - /* Update the read offset */ - pDev->nOfft += (sxu32)n; - if( pDev->nOfft >= SyBlobLength(&pDev->sBuffer) ){ - /* Reset the working buffer so that we avoid excessive memory allocation */ - SyBlobReset(&pDev->sBuffer); - pDev->nOfft = 0; - } - nLen -= n; - if( nLen < 1 ){ - /* All done */ - return n; - } - /* Advance the cursor */ - zBuf += n; - } - /* Read without buffering */ - nRead = pStream->xRead(pDev->pHandle, zBuf, nLen); - if( nRead > 0 ){ - n += nRead; - }else if( n < 1 ){ - /* EOF or IO error */ - return nRead; - } - return n; -} -/* - * Extract a single line from the buffered input. - */ -static sxi32 GetLine(io_private *pDev, jx9_int64 *pLen, const char **pzLine) -{ - const char *zIn, *zEnd, *zPtr; - zIn = (const char *)SyBlobDataAt(&pDev->sBuffer, pDev->nOfft); - zEnd = &zIn[SyBlobLength(&pDev->sBuffer)-pDev->nOfft]; - zPtr = zIn; - while( zIn < zEnd ){ - if( zIn[0] == '\n' ){ - /* Line found */ - zIn++; /* Include the line ending as requested by the JX9 specification */ - *pLen = (jx9_int64)(zIn-zPtr); - *pzLine = zPtr; - return SXRET_OK; - } - zIn++; - } - /* No line were found */ - return SXERR_NOTFOUND; -} -/* - * Read a single line from the underlying IO stream device. - */ -static jx9_int64 StreamReadLine(io_private *pDev, const char **pzData, jx9_int64 nMaxLen) -{ - const jx9_io_stream *pStream = pDev->pStream; - char zBuf[8192]; - jx9_int64 n; - sxi32 rc; - n = 0; - if( pDev->nOfft >= SyBlobLength(&pDev->sBuffer) ){ - /* Reset the working buffer so that we avoid excessive memory allocation */ - SyBlobReset(&pDev->sBuffer); - pDev->nOfft = 0; - } - if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){ - /* Check if there is a line */ - rc = GetLine(pDev, &n, pzData); - if( rc == SXRET_OK ){ - /* Got line, update the cursor */ - pDev->nOfft += (sxu32)n; - return n; - } - } - /* Perform the read operation until a new line is extracted or length - * limit is reached. - */ - for(;;){ - n = pStream->xRead(pDev->pHandle, zBuf, (nMaxLen > 0 && nMaxLen < sizeof(zBuf)) ? nMaxLen : sizeof(zBuf)); - if( n < 1 ){ - /* EOF or IO error */ - break; - } - /* Append the data just read */ - SyBlobAppend(&pDev->sBuffer, zBuf, (sxu32)n); - /* Try to extract a line */ - rc = GetLine(pDev, &n, pzData); - if( rc == SXRET_OK ){ - /* Got one, return immediately */ - pDev->nOfft += (sxu32)n; - return n; - } - if( nMaxLen > 0 && (SyBlobLength(&pDev->sBuffer) - pDev->nOfft >= nMaxLen) ){ - /* Read limit reached, return the available data */ - *pzData = (const char *)SyBlobDataAt(&pDev->sBuffer, pDev->nOfft); - n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft; - /* Reset the working buffer */ - SyBlobReset(&pDev->sBuffer); - pDev->nOfft = 0; - return n; - } - } - if( SyBlobLength(&pDev->sBuffer) - pDev->nOfft > 0 ){ - /* Read limit reached, return the available data */ - *pzData = (const char *)SyBlobDataAt(&pDev->sBuffer, pDev->nOfft); - n = SyBlobLength(&pDev->sBuffer) - pDev->nOfft; - /* Reset the working buffer */ - SyBlobReset(&pDev->sBuffer); - pDev->nOfft = 0; - } - return n; -} -/* - * Open an IO stream handle. - * Notes on stream: - * According to the JX9 reference manual. - * In its simplest definition, a stream is a resource object which exhibits streamable behavior. - * That is, it can be read from or written to in a linear fashion, and may be able to fseek() - * to an arbitrary locations within the stream. - * A wrapper is additional code which tells the stream how to handle specific protocols/encodings. - * For example, the http wrapper knows how to translate a URL into an HTTP/1.0 request for a file - * on a remote server. - * A stream is referenced as: scheme://target - * scheme(string) - The name of the wrapper to be used. Examples include: file, http... - * If no wrapper is specified, the function default is used (typically file://). - * target - Depends on the wrapper used. For filesystem related streams this is typically a path - * and filename of the desired file. For network related streams this is typically a hostname, often - * with a path appended. - * - * Note that JX9 IO streams looks like JX9 streams but their implementation differ greately. - * Please refer to the official documentation for a full discussion. - * This function return a handle on success. Otherwise null. - */ -JX9_PRIVATE void * jx9StreamOpenHandle(jx9_vm *pVm, const jx9_io_stream *pStream, const char *zFile, - int iFlags, int use_include, jx9_value *pResource, int bPushInclude, int *pNew) -{ - void *pHandle = 0; /* cc warning */ - SyString sFile; - int rc; - if( pStream == 0 ){ - /* No such stream device */ - return 0; - } - SyStringInitFromBuf(&sFile, zFile, SyStrlen(zFile)); - if( use_include ){ - if( sFile.zString[0] == '/' || -#ifdef __WINNT__ - (sFile.nByte > 2 && sFile.zString[1] == ':' && (sFile.zString[2] == '\\' || sFile.zString[2] == '/') ) || -#endif - (sFile.nByte > 1 && sFile.zString[0] == '.' && sFile.zString[1] == '/') || - (sFile.nByte > 2 && sFile.zString[0] == '.' && sFile.zString[1] == '.' && sFile.zString[2] == '/') ){ - /* Open the file directly */ - rc = pStream->xOpen(zFile, iFlags, pResource, &pHandle); - }else{ - SyString *pPath; - SyBlob sWorker; -#ifdef __WINNT__ - static const int c = '\\'; -#else - static const int c = '/'; -#endif - /* Init the path builder working buffer */ - SyBlobInit(&sWorker, &pVm->sAllocator); - /* Build a path from the set of include path */ - SySetResetCursor(&pVm->aPaths); - rc = SXERR_IO; - while( SXRET_OK == SySetGetNextEntry(&pVm->aPaths, (void **)&pPath) ){ - /* Build full path */ - SyBlobFormat(&sWorker, "%z%c%z", pPath, c, &sFile); - /* Append null terminator */ - if( SXRET_OK != SyBlobNullAppend(&sWorker) ){ - continue; - } - /* Try to open the file */ - rc = pStream->xOpen((const char *)SyBlobData(&sWorker), iFlags, pResource, &pHandle); - if( rc == JX9_OK ){ - if( bPushInclude ){ - /* Mark as included */ - jx9VmPushFilePath(pVm, (const char *)SyBlobData(&sWorker), SyBlobLength(&sWorker), FALSE, pNew); - } - break; - } - /* Reset the working buffer */ - SyBlobReset(&sWorker); - /* Check the next path */ - } - SyBlobRelease(&sWorker); - } - if( rc == JX9_OK ){ - if( bPushInclude ){ - /* Mark as included */ - jx9VmPushFilePath(pVm, sFile.zString, sFile.nByte, FALSE, pNew); - } - } - }else{ - /* Open the URI direcly */ - rc = pStream->xOpen(zFile, iFlags, pResource, &pHandle); - } - if( rc != JX9_OK ){ - /* IO error */ - return 0; - } - /* Return the file handle */ - return pHandle; -} -/* - * Read the whole contents of an open IO stream handle [i.e local file/URL..] - * Store the read data in the given BLOB (last argument). - * The read operation is stopped when he hit the EOF or an IO error occurs. - */ -JX9_PRIVATE sxi32 jx9StreamReadWholeFile(void *pHandle, const jx9_io_stream *pStream, SyBlob *pOut) -{ - jx9_int64 nRead; - char zBuf[8192]; /* 8K */ - int rc; - /* Perform the requested operation */ - for(;;){ - nRead = pStream->xRead(pHandle, zBuf, sizeof(zBuf)); - if( nRead < 1 ){ - /* EOF or IO error */ - break; - } - /* Append contents */ - rc = SyBlobAppend(pOut, zBuf, (sxu32)nRead); - if( rc != SXRET_OK ){ - break; - } - } - return SyBlobLength(pOut) > 0 ? SXRET_OK : -1; -} -/* - * Close an open IO stream handle [i.e local file/URI..]. - */ -JX9_PRIVATE void jx9StreamCloseHandle(const jx9_io_stream *pStream, void *pHandle) -{ - if( pStream->xClose ){ - pStream->xClose(pHandle); - } -} -/* - * string fgetc(resource $handle) - * Gets a character from the given file pointer. - * Parameters - * $handle - * The file pointer. - * Return - * Returns a string containing a single character read from the file - * pointed to by handle. Returns FALSE on EOF. - * WARNING - * This operation is extremely slow.Avoid using it. - */ -static int jx9Builtin_fgetc(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int c, n; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - n = (int)StreamRead(pDev, (void *)&c, sizeof(char)); - /* IO result */ - if( n < 1 ){ - /* EOF or error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the string holding the character */ - jx9_result_string(pCtx, (const char *)&c, sizeof(char)); - } - return JX9_OK; -} -/* - * string fgets(resource $handle[, int64 $length ]) - * Gets line from file pointer. - * Parameters - * $handle - * The file pointer. - * $length - * Reading ends when length - 1 bytes have been read, on a newline - * (which is included in the return value), or on EOF (whichever comes first). - * If no length is specified, it will keep reading from the stream until it reaches - * the end of the line. - * Return - * Returns a string of up to length - 1 bytes read from the file pointed to by handle. - * If there is no more data to read in the file pointer, then FALSE is returned. - * If an error occurs, FALSE is returned. - */ -static int jx9Builtin_fgets(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zLine; - io_private *pDev; - jx9_int64 n, nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = -1; - if( nArg > 1 ){ - /* Maximum data to read */ - nLen = jx9_value_to_int64(apArg[1]); - } - /* Perform the requested operation */ - n = StreamReadLine(pDev, &zLine, nLen); - if( n < 1 ){ - /* EOF or IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return the freshly extracted line */ - jx9_result_string(pCtx, zLine, (int)n); - } - return JX9_OK; -} -/* - * string fread(resource $handle, int64 $length) - * Binary-safe file read. - * Parameters - * $handle - * The file pointer. - * $length - * Up to length number of bytes read. - * Return - * The data readen on success or FALSE on failure. - */ -static int jx9Builtin_fread(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 nRead; - void *pBuf; - int nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = 4096; - if( nArg > 1 ){ - nLen = jx9_value_to_int(apArg[1]); - if( nLen < 1 ){ - /* Invalid length, set a default length */ - nLen = 4096; - } - } - /* Allocate enough buffer */ - pBuf = jx9_context_alloc_chunk(pCtx, (unsigned int)nLen, FALSE, FALSE); - if( pBuf == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - nRead = StreamRead(pDev, pBuf, (jx9_int64)nLen); - if( nRead < 1 ){ - /* Nothing read, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Make a copy of the data just read */ - jx9_result_string(pCtx, (const char *)pBuf, (int)nRead); - } - /* Release the buffer */ - jx9_context_free_chunk(pCtx, pBuf); - return JX9_OK; -} -/* - * array fgetcsv(resource $handle [, int $length = 0 - * [, string $delimiter = ', '[, string $enclosure = '"'[, string $escape='\\']]]]) - * Gets line from file pointer and parse for CSV fields. - * Parameters - * $handle - * The file pointer. - * $length - * Reading ends when length - 1 bytes have been read, on a newline - * (which is included in the return value), or on EOF (whichever comes first). - * If no length is specified, it will keep reading from the stream until it reaches - * the end of the line. - * $delimiter - * Set the field delimiter (one character only). - * $enclosure - * Set the field enclosure character (one character only). - * $escape - * Set the escape character (one character only). Defaults as a backslash (\) - * Return - * Returns a string of up to length - 1 bytes read from the file pointed to by handle. - * If there is no more data to read in the file pointer, then FALSE is returned. - * If an error occurs, FALSE is returned. - */ -static int jx9Builtin_fgetcsv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zLine; - io_private *pDev; - jx9_int64 n, nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = -1; - if( nArg > 1 ){ - /* Maximum data to read */ - nLen = jx9_value_to_int64(apArg[1]); - } - /* Perform the requested operation */ - n = StreamReadLine(pDev, &zLine, nLen); - if( n < 1 ){ - /* EOF or IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - jx9_value *pArray; - int delim = ','; /* Delimiter */ - int encl = '"' ; /* Enclosure */ - int escape = '\\'; /* Escape character */ - if( nArg > 2 ){ - const char *zPtr; - int i; - if( jx9_value_is_string(apArg[2]) ){ - /* Extract the delimiter */ - zPtr = jx9_value_to_string(apArg[2], &i); - if( i > 0 ){ - delim = zPtr[0]; - } - } - if( nArg > 3 ){ - if( jx9_value_is_string(apArg[3]) ){ - /* Extract the enclosure */ - zPtr = jx9_value_to_string(apArg[3], &i); - if( i > 0 ){ - encl = zPtr[0]; - } - } - if( nArg > 4 ){ - if( jx9_value_is_string(apArg[4]) ){ - /* Extract the escape character */ - zPtr = jx9_value_to_string(apArg[4], &i); - if( i > 0 ){ - escape = zPtr[0]; - } - } - } - } - } - /* Create our array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_null(pCtx); - return JX9_OK; - } - /* Parse the raw input */ - jx9ProcessCsv(zLine, (int)n, delim, encl, escape, jx9CsvConsumer, pArray); - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - } - return JX9_OK; -} -/* - * string fgetss(resource $handle [, int $length [, string $allowable_tags ]]) - * Gets line from file pointer and strip HTML tags. - * Parameters - * $handle - * The file pointer. - * $length - * Reading ends when length - 1 bytes have been read, on a newline - * (which is included in the return value), or on EOF (whichever comes first). - * If no length is specified, it will keep reading from the stream until it reaches - * the end of the line. - * $allowable_tags - * You can use the optional second parameter to specify tags which should not be stripped. - * Return - * Returns a string of up to length - 1 bytes read from the file pointed to by - * handle, with all HTML and JX9 code stripped. If an error occurs, returns FALSE. - */ -static int jx9Builtin_fgetss(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zLine; - io_private *pDev; - jx9_int64 n, nLen; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nLen = -1; - if( nArg > 1 ){ - /* Maximum data to read */ - nLen = jx9_value_to_int64(apArg[1]); - } - /* Perform the requested operation */ - n = StreamReadLine(pDev, &zLine, nLen); - if( n < 1 ){ - /* EOF or IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - const char *zTaglist = 0; - int nTaglen = 0; - if( nArg > 2 && jx9_value_is_string(apArg[2]) ){ - /* Allowed tag */ - zTaglist = jx9_value_to_string(apArg[2], &nTaglen); - } - /* Process data just read */ - jx9StripTagsFromString(pCtx, zLine, (int)n, zTaglist, nTaglen); - } - return JX9_OK; -} -/* - * string readdir(resource $dir_handle) - * Read entry from directory handle. - * Parameter - * $dir_handle - * The directory handle resource previously opened with opendir(). - * Return - * Returns the filename on success or FALSE on failure. - */ -static int jx9Builtin_readdir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xReadDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - jx9_result_bool(pCtx, 0); - /* Perform the requested operation */ - rc = pStream->xReadDir(pDev->pHandle, pCtx); - if( rc != JX9_OK ){ - /* Return FALSE */ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * void rewinddir(resource $dir_handle) - * Rewind directory handle. - * Parameter - * $dir_handle - * The directory handle resource previously opened with opendir(). - * Return - * FALSE on failure. - */ -static int jx9Builtin_rewinddir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xRewindDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - pStream->xRewindDir(pDev->pHandle); - return JX9_OK; - } -/* Forward declaration */ -static void InitIOPrivate(jx9_vm *pVm, const jx9_io_stream *pStream, io_private *pOut); -static void ReleaseIOPrivate(jx9_context *pCtx, io_private *pDev); -/* - * void closedir(resource $dir_handle) - * Close directory handle. - * Parameter - * $dir_handle - * The directory handle resource previously opened with opendir(). - * Return - * FALSE on failure. - */ -static int jx9Builtin_closedir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xCloseDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - pStream->xCloseDir(pDev->pHandle); - /* Release the private stucture */ - ReleaseIOPrivate(pCtx, pDev); - jx9MemObjRelease(apArg[0]); - return JX9_OK; - } -/* - * resource opendir(string $path[, resource $context]) - * Open directory handle. - * Parameters - * $path - * The directory path that is to be opened. - * $context - * A context stream resource. - * Return - * A directory handle resource on success, or FALSE on failure. - */ -static int jx9Builtin_opendir(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zPath; - io_private *pDev; - int iLen, rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a directory path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the target path */ - zPath = jx9_value_to_string(apArg[0], &iLen); - /* Try to extract a stream */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zPath, iLen); - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "No stream device is associated with the given path(%s)", zPath); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( pStream->xOpenDir == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pStream->zName - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Allocate a new IO private instance */ - pDev = (io_private *)jx9_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); - if( pDev == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Initialize the structure */ - InitIOPrivate(pCtx->pVm, pStream, pDev); - /* Open the target directory */ - rc = pStream->xOpenDir(zPath, nArg > 1 ? apArg[1] : 0, &pDev->pHandle); - if( rc != JX9_OK ){ - /* IO error, return FALSE */ - ReleaseIOPrivate(pCtx, pDev); - jx9_result_bool(pCtx, 0); - }else{ - /* Return the handle as a resource */ - jx9_result_resource(pCtx, pDev); - } - return JX9_OK; -} -/* - * int readfile(string $filename[, bool $use_include_path = false [, resource $context ]]) - * Reads a file and writes it to the output buffer. - * Parameters - * $filename - * The filename being read. - * $use_include_path - * You can use the optional second parameter and set it to - * TRUE, if you want to search for the file in the include_path, too. - * $context - * A context stream resource. - * Return - * The number of bytes read from the file on success or FALSE on failure. - */ -static int jx9Builtin_readfile(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int use_include = FALSE; - const jx9_io_stream *pStream; - jx9_int64 n, nRead; - const char *zFile; - char zBuf[8192]; - void *pHandle; - int rc, nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 1 ){ - use_include = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, - use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - nRead = 0; - for(;;){ - n = pStream->xRead(pHandle, zBuf, sizeof(zBuf)); - if( n < 1 ){ - /* EOF or IO error, break immediately */ - break; - } - /* Output data */ - rc = jx9_context_output(pCtx, zBuf, (int)n); - if( rc == JX9_ABORT ){ - break; - } - /* Increment counter */ - nRead += n; - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Total number of bytes readen */ - jx9_result_int64(pCtx, nRead); - return JX9_OK; -} -/* - * string file_get_contents(string $filename[, bool $use_include_path = false - * [, resource $context [, int $offset = -1 [, int $maxlen ]]]]) - * Reads entire file into a string. - * Parameters - * $filename - * The filename being read. - * $use_include_path - * You can use the optional second parameter and set it to - * TRUE, if you want to search for the file in the include_path, too. - * $context - * A context stream resource. - * $offset - * The offset where the reading starts on the original stream. - * $maxlen - * Maximum length of data read. The default is to read until end of file - * is reached. Note that this parameter is applied to the stream processed by the filters. - * Return - * The function returns the read data or FALSE on failure. - */ -static int jx9Builtin_file_get_contents(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - jx9_int64 n, nRead, nMaxlen; - int use_include = FALSE; - const char *zFile; - char zBuf[8192]; - void *pHandle; - int nLen; - - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - nMaxlen = -1; - if( nArg > 1 ){ - use_include = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 3 ){ - /* Extract the offset */ - n = jx9_value_to_int64(apArg[3]); - if( n > 0 ){ - if( pStream->xSeek ){ - /* Seek to the desired offset */ - pStream->xSeek(pHandle, n, 0/*SEEK_SET*/); - } - } - if( nArg > 4 ){ - /* Maximum data to read */ - nMaxlen = jx9_value_to_int64(apArg[4]); - } - } - /* Perform the requested operation */ - nRead = 0; - for(;;){ - n = pStream->xRead(pHandle, zBuf, - (nMaxlen > 0 && (nMaxlen < sizeof(zBuf))) ? nMaxlen : sizeof(zBuf)); - if( n < 1 ){ - /* EOF or IO error, break immediately */ - break; - } - /* Append data */ - jx9_result_string(pCtx, zBuf, (int)n); - /* Increment read counter */ - nRead += n; - if( nMaxlen > 0 && nRead >= nMaxlen ){ - /* Read limit reached */ - break; - } - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Check if we have read something */ - if( jx9_context_result_buf_length(pCtx) < 1 ){ - /* Nothing read, return FALSE */ - jx9_result_bool(pCtx, 0); - } - return JX9_OK; -} -/* - * int file_put_contents(string $filename, mixed $data[, int $flags = 0[, resource $context]]) - * Write a string to a file. - * Parameters - * $filename - * Path to the file where to write the data. - * $data - * The data to write(Must be a string). - * $flags - * The value of flags can be any combination of the following - * flags, joined with the binary OR (|) operator. - * FILE_USE_INCLUDE_PATH Search for filename in the include directory. See include_path for more information. - * FILE_APPEND If file filename already exists, append the data to the file instead of overwriting it. - * LOCK_EX Acquire an exclusive lock on the file while proceeding to the writing. - * context - * A context stream resource. - * Return - * The function returns the number of bytes that were written to the file, or FALSE on failure. - */ -static int jx9Builtin_file_put_contents(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - int use_include = FALSE; - const jx9_io_stream *pStream; - const char *zFile; - const char *zData; - int iOpenFlags; - void *pHandle; - int iFlags; - int nLen; - - if( nArg < 2 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Data to write */ - zData = jx9_value_to_string(apArg[1], &nLen); - if( nLen < 1 ){ - /* Nothing to write, return immediately */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the file in read-write mode */ - iOpenFlags = JX9_IO_OPEN_CREATE|JX9_IO_OPEN_RDWR|JX9_IO_OPEN_TRUNC; - /* Extract the flags */ - iFlags = 0; - if( nArg > 2 ){ - iFlags = jx9_value_to_int(apArg[2]); - if( iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/){ - use_include = TRUE; - } - if( iFlags & 0x08 /* FILE_APPEND */){ - /* If the file already exists, append the data to the file - * instead of overwriting it. - */ - iOpenFlags &= ~JX9_IO_OPEN_TRUNC; - /* Append mode */ - iOpenFlags |= JX9_IO_OPEN_APPEND; - } - } - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, iOpenFlags, use_include, - nArg > 3 ? apArg[3] : 0, FALSE, FALSE); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( pStream->xWrite ){ - jx9_int64 n; - if( (iFlags & 0x01/* LOCK_EX */) && pStream->xLock ){ - /* Try to acquire an exclusive lock */ - pStream->xLock(pHandle, 1/* LOCK_EX */); - } - /* Perform the write operation */ - n = pStream->xWrite(pHandle, (const void *)zData, nLen); - if( n < 1 ){ - /* IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Total number of bytes written */ - jx9_result_int64(pCtx, n); - } - }else{ - /* Read-only stream */ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, - "Read-only stream(%s): Cannot perform write operation", - pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - } - /* Close the handle */ - jx9StreamCloseHandle(pStream, pHandle); - return JX9_OK; -} -/* - * array file(string $filename[, int $flags = 0[, resource $context]]) - * Reads entire file into an array. - * Parameters - * $filename - * The filename being read. - * $flags - * The optional parameter flags can be one, or more, of the following constants: - * FILE_USE_INCLUDE_PATH - * Search for the file in the include_path. - * FILE_IGNORE_NEW_LINES - * Do not add newline at the end of each array element - * FILE_SKIP_EMPTY_LINES - * Skip empty lines - * $context - * A context stream resource. - * Return - * The function returns the read data or FALSE on failure. - */ -static int jx9Builtin_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zFile, *zPtr, *zEnd, *zBuf; - jx9_value *pArray, *pLine; - const jx9_io_stream *pStream; - int use_include = 0; - io_private *pDev; - jx9_int64 n; - int iFlags; - int nLen; - - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Allocate a new IO private instance */ - pDev = (io_private *)jx9_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); - if( pDev == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Initialize the structure */ - InitIOPrivate(pCtx->pVm, pStream, pDev); - iFlags = 0; - if( nArg > 1 ){ - iFlags = jx9_value_to_int(apArg[1]); - } - if( iFlags & 0x01 /*FILE_USE_INCLUDE_PATH*/ ){ - use_include = TRUE; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pLine = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pLine == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the file in read-only mode */ - pDev->pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, use_include, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pDev->pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - /* Don't worry about freeing memory, everything will be released automatically - * as soon we return from this function. - */ - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - /* Try to extract a line */ - n = StreamReadLine(pDev, &zBuf, -1); - if( n < 1 ){ - /* EOF or IO error */ - break; - } - /* Reset the cursor */ - jx9_value_reset_string_cursor(pLine); - /* Remove line ending if requested by the caller */ - zPtr = zBuf; - zEnd = &zBuf[n]; - if( iFlags & 0x02 /* FILE_IGNORE_NEW_LINES */ ){ - /* Ignore trailig lines */ - while( zPtr < zEnd && (zEnd[-1] == '\n' -#ifdef __WINNT__ - || zEnd[-1] == '\r' -#endif - )){ - n--; - zEnd--; - } - } - if( iFlags & 0x04 /* FILE_SKIP_EMPTY_LINES */ ){ - /* Ignore empty lines */ - while( zPtr < zEnd && (unsigned char)zPtr[0] < 0xc0 && SyisSpace(zPtr[0]) ){ - zPtr++; - } - if( zPtr >= zEnd ){ - /* Empty line */ - continue; - } - } - jx9_value_string(pLine, zBuf, (int)(zEnd-zBuf)); - /* Insert line */ - jx9_array_add_elem(pArray, 0/* Automatic index assign*/, pLine); - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pDev->pHandle); - /* Release the io_private instance */ - ReleaseIOPrivate(pCtx, pDev); - /* Return the created array */ - jx9_result_value(pCtx, pArray); - return JX9_OK; -} -/* - * bool copy(string $source, string $dest[, resource $context ] ) - * Makes a copy of the file source to dest. - * Parameters - * $source - * Path to the source file. - * $dest - * The destination path. If dest is a URL, the copy operation - * may fail if the wrapper does not support overwriting of existing files. - * $context - * A context stream resource. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Builtin_copy(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pSin, *pSout; - const char *zFile; - char zBuf[8192]; - void *pIn, *pOut; - jx9_int64 n; - int nLen; - if( nArg < 2 || !jx9_value_is_string(apArg[0]) || !jx9_value_is_string(apArg[1])){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a source and a destination path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the source name */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pSin = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pSin == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the source file in a read-only mode */ - pIn = jx9StreamOpenHandle(pCtx->pVm, pSin, zFile, JX9_IO_OPEN_RDONLY, FALSE, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pIn == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening source: '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the destination name */ - zFile = jx9_value_to_string(apArg[1], &nLen); - /* Point to the target IO stream device */ - pSout = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pSout == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - jx9StreamCloseHandle(pSin, pIn); - return JX9_OK; - } - if( pSout->xWrite == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pSin->zName - ); - jx9_result_bool(pCtx, 0); - jx9StreamCloseHandle(pSin, pIn); - return JX9_OK; - } - /* Try to open the destination file in a read-write mode */ - pOut = jx9StreamOpenHandle(pCtx->pVm, pSout, zFile, - JX9_IO_OPEN_CREATE|JX9_IO_OPEN_TRUNC|JX9_IO_OPEN_RDWR, FALSE, nArg > 2 ? apArg[2] : 0, FALSE, 0); - if( pOut == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening destination: '%s'", zFile); - jx9_result_bool(pCtx, 0); - jx9StreamCloseHandle(pSin, pIn); - return JX9_OK; - } - /* Perform the requested operation */ - for(;;){ - /* Read from source */ - n = pSin->xRead(pIn, zBuf, sizeof(zBuf)); - if( n < 1 ){ - /* EOF or IO error, break immediately */ - break; - } - /* Write to dest */ - n = pSout->xWrite(pOut, zBuf, n); - if( n < 1 ){ - /* IO error, break immediately */ - break; - } - } - /* Close the streams */ - jx9StreamCloseHandle(pSin, pIn); - jx9StreamCloseHandle(pSout, pOut); - /* Return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * array fstat(resource $handle) - * Gets information about a file using an open file pointer. - * Parameters - * $handle - * The file pointer. - * Return - * Returns an array with the statistics of the file or FALSE on failure. - */ -static int jx9Builtin_fstat(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray, *pValue; - const jx9_io_stream *pStream; - io_private *pDev; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /* Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xStat == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create the array and the working value */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pValue == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - pStream->xStat(pDev->pHandle, pArray, pValue); - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - /* Don't worry about freeing memory here, everything will be - * released automatically as soon we return from this function. - */ - return JX9_OK; -} -/* - * int fwrite(resource $handle, string $string[, int $length]) - * Writes the contents of string to the file stream pointed to by handle. - * Parameters - * $handle - * The file pointer. - * $string - * The string that is to be written. - * $length - * If the length argument is given, writing will stop after length bytes have been written - * or the end of string is reached, whichever comes first. - * Return - * Returns the number of bytes written, or FALSE on error. - */ -static int jx9Builtin_fwrite(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zString; - io_private *pDev; - int nLen, n; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /* Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xWrite == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the data to write */ - zString = jx9_value_to_string(apArg[1], &nLen); - if( nArg > 2 ){ - /* Maximum data length to write */ - n = jx9_value_to_int(apArg[2]); - if( n >= 0 && n < nLen ){ - nLen = n; - } - } - if( nLen < 1 ){ - /* Nothing to write */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - n = (int)pStream->xWrite(pDev->pHandle, (const void *)zString, nLen); - if( n < 0 ){ - /* IO error, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* #Bytes written */ - jx9_result_int(pCtx, n); - } - return JX9_OK; -} -/* - * bool flock(resource $handle, int $operation) - * Portable advisory file locking. - * Parameters - * $handle - * The file pointer. - * $operation - * operation is one of the following: - * LOCK_SH to acquire a shared lock (reader). - * LOCK_EX to acquire an exclusive lock (writer). - * LOCK_UN to release a lock (shared or exclusive). - * Return - * Returns TRUE on success or FALSE on failure. - */ -static int jx9Builtin_flock(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - int nLock; - int rc; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xLock == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Requested lock operation */ - nLock = jx9_value_to_int(apArg[1]); - /* Lock operation */ - rc = pStream->xLock(pDev->pHandle, nLock); - /* IO result */ - jx9_result_bool(pCtx, rc == JX9_OK); - return JX9_OK; -} -/* - * int fpassthru(resource $handle) - * Output all remaining data on a file pointer. - * Parameters - * $handle - * The file pointer. - * Return - * Total number of characters read from handle and passed through - * to the output on success or FALSE on failure. - */ -static int jx9Builtin_fpassthru(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_int64 n, nRead; - char zBuf[8192]; - int rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Perform the requested operation */ - nRead = 0; - for(;;){ - n = StreamRead(pDev, zBuf, sizeof(zBuf)); - if( n < 1 ){ - /* Error or EOF */ - break; - } - /* Increment the read counter */ - nRead += n; - /* Output data */ - rc = jx9_context_output(pCtx, zBuf, (int)nRead /* FIXME: 64-bit issues */); - if( rc == JX9_ABORT ){ - /* Consumer callback request an operation abort */ - break; - } - } - /* Total number of bytes readen */ - jx9_result_int64(pCtx, nRead); - return JX9_OK; -} -/* CSV reader/writer private data */ -struct csv_data -{ - int delimiter; /* Delimiter. Default ', ' */ - int enclosure; /* Enclosure. Default '"'*/ - io_private *pDev; /* Open stream handle */ - int iCount; /* Counter */ -}; -/* - * The following callback is used by the fputcsv() function inorder to iterate - * throw array entries and output CSV data based on the current key and it's - * associated data. - */ -static int csv_write_callback(jx9_value *pKey, jx9_value *pValue, void *pUserData) -{ - struct csv_data *pData = (struct csv_data *)pUserData; - const char *zData; - int nLen, c2; - sxu32 n; - /* Point to the raw data */ - zData = jx9_value_to_string(pValue, &nLen); - if( nLen < 1 ){ - /* Nothing to write */ - return JX9_OK; - } - if( pData->iCount > 0 ){ - /* Write the delimiter */ - pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->delimiter, sizeof(char)); - } - n = 1; - c2 = 0; - if( SyByteFind(zData, (sxu32)nLen, pData->delimiter, 0) == SXRET_OK || - SyByteFind(zData, (sxu32)nLen, pData->enclosure, &n) == SXRET_OK ){ - c2 = 1; - if( n == 0 ){ - c2 = 2; - } - /* Write the enclosure */ - pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char)); - if( c2 > 1 ){ - pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char)); - } - } - /* Write the data */ - if( pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)zData, (jx9_int64)nLen) < 1 ){ - SXUNUSED(pKey); /* cc warning */ - return JX9_ABORT; - } - if( c2 > 0 ){ - /* Write the enclosure */ - pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char)); - if( c2 > 1 ){ - pData->pDev->pStream->xWrite(pData->pDev->pHandle, (const void *)&pData->enclosure, sizeof(char)); - } - } - pData->iCount++; - return JX9_OK; -} -/* - * int fputcsv(resource $handle, array $fields[, string $delimiter = ', '[, string $enclosure = '"' ]]) - * Format line as CSV and write to file pointer. - * Parameters - * $handle - * Open file handle. - * $fields - * An array of values. - * $delimiter - * The optional delimiter parameter sets the field delimiter (one character only). - * $enclosure - * The optional enclosure parameter sets the field enclosure (one character only). - */ -static int jx9Builtin_fputcsv(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - struct csv_data sCsv; - io_private *pDev; - char *zEol; - int eolen; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_json_array(apArg[1]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Missing/Invalid arguments"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 || pStream->xWrite == 0){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Set default csv separator */ - sCsv.delimiter = ','; - sCsv.enclosure = '"'; - sCsv.pDev = pDev; - sCsv.iCount = 0; - if( nArg > 2 ){ - /* User delimiter */ - const char *z; - int n; - z = jx9_value_to_string(apArg[2], &n); - if( n > 0 ){ - sCsv.delimiter = z[0]; - } - if( nArg > 3 ){ - z = jx9_value_to_string(apArg[3], &n); - if( n > 0 ){ - sCsv.enclosure = z[0]; - } - } - } - /* Iterate throw array entries and write csv data */ - jx9_array_walk(apArg[1], csv_write_callback, &sCsv); - /* Write a line ending */ -#ifdef __WINNT__ - zEol = "\r\n"; - eolen = (int)sizeof("\r\n")-1; -#else - /* Assume UNIX LF */ - zEol = "\n"; - eolen = (int)sizeof(char); -#endif - pDev->pStream->xWrite(pDev->pHandle, (const void *)zEol, eolen); - return JX9_OK; -} -/* - * fprintf, vfprintf private data. - * An instance of the following structure is passed to the formatted - * input consumer callback defined below. - */ -typedef struct fprintf_data fprintf_data; -struct fprintf_data -{ - io_private *pIO; /* IO stream */ - jx9_int64 nCount; /* Total number of bytes written */ -}; -/* - * Callback [i.e: Formatted input consumer] for the fprintf function. - */ -static int fprintfConsumer(jx9_context *pCtx, const char *zInput, int nLen, void *pUserData) -{ - fprintf_data *pFdata = (fprintf_data *)pUserData; - jx9_int64 n; - /* Write the formatted data */ - n = pFdata->pIO->pStream->xWrite(pFdata->pIO->pHandle, (const void *)zInput, nLen); - if( n < 1 ){ - SXUNUSED(pCtx); /* cc warning */ - /* IO error, abort immediately */ - return SXERR_ABORT; - } - /* Increment counter */ - pFdata->nCount += n; - return JX9_OK; -} -/* - * int fprintf(resource $handle, string $format[, mixed $args [, mixed $... ]]) - * Write a formatted string to a stream. - * Parameters - * $handle - * The file pointer. - * $format - * String format (see sprintf()). - * Return - * The length of the written string. - */ -static int jx9Builtin_fprintf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - fprintf_data sFdata; - const char *zFormat; - io_private *pDev; - int nLen; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_string(apArg[1]) ){ - /* Missing/Invalid arguments, return zero */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Invalid arguments"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pDev->pStream ? pDev->pStream->zName : "null_stream" - ); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[1], &nLen); - if( nLen < 1 ){ - /* Empty string, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Prepare our private data */ - sFdata.nCount = 0; - sFdata.pIO = pDev; - /* Format the string */ - jx9InputFormat(fprintfConsumer, pCtx, zFormat, nLen, nArg - 1, &apArg[1], (void *)&sFdata, FALSE); - /* Return total number of bytes written */ - jx9_result_int64(pCtx, sFdata.nCount); - return JX9_OK; -} -/* - * int vfprintf(resource $handle, string $format, array $args) - * Write a formatted string to a stream. - * Parameters - * $handle - * The file pointer. - * $format - * String format (see sprintf()). - * $args - * User arguments. - * Return - * The length of the written string. - */ -static int jx9Builtin_vfprintf(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - fprintf_data sFdata; - const char *zFormat; - jx9_hashmap *pMap; - io_private *pDev; - SySet sArg; - int n, nLen; - if( nArg < 3 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_string(apArg[1]) || !jx9_value_is_json_array(apArg[2]) ){ - /* Missing/Invalid arguments, return zero */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Invalid arguments"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - if( pDev->pStream == 0 || pDev->pStream->xWrite == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device", - jx9_function_name(pCtx), pDev->pStream ? pDev->pStream->zName : "null_stream" - ); - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Extract the string format */ - zFormat = jx9_value_to_string(apArg[1], &nLen); - if( nLen < 1 ){ - /* Empty string, return zero */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to hashmap */ - pMap = (jx9_hashmap *)apArg[2]->x.pOther; - /* Extract arguments from the hashmap */ - n = jx9HashmapValuesToSet(pMap, &sArg); - /* Prepare our private data */ - sFdata.nCount = 0; - sFdata.pIO = pDev; - /* Format the string */ - jx9InputFormat(fprintfConsumer, pCtx, zFormat, nLen, n, (jx9_value **)SySetBasePtr(&sArg), (void *)&sFdata, TRUE); - /* Return total number of bytes written*/ - jx9_result_int64(pCtx, sFdata.nCount); - SySetRelease(&sArg); - return JX9_OK; -} -/* - * Convert open modes (string passed to the fopen() function) [i.e: 'r', 'w+', 'a', ...] into JX9 flags. - * According to the JX9 reference manual: - * The mode parameter specifies the type of access you require to the stream. It may be any of the following - * 'r' Open for reading only; place the file pointer at the beginning of the file. - * 'r+' Open for reading and writing; place the file pointer at the beginning of the file. - * 'w' Open for writing only; place the file pointer at the beginning of the file and truncate the file - * to zero length. If the file does not exist, attempt to create it. - * 'w+' Open for reading and writing; place the file pointer at the beginning of the file and truncate - * the file to zero length. If the file does not exist, attempt to create it. - * 'a' Open for writing only; place the file pointer at the end of the file. If the file does not - * exist, attempt to create it. - * 'a+' Open for reading and writing; place the file pointer at the end of the file. If the file does - * not exist, attempt to create it. - * 'x' Create and open for writing only; place the file pointer at the beginning of the file. If the file - * already exists, - * the fopen() call will fail by returning FALSE and generating an error of level E_WARNING. If the file - * does not exist attempt to create it. This is equivalent to specifying O_EXCL|O_CREAT flags for - * the underlying open(2) system call. - * 'x+' Create and open for reading and writing; otherwise it has the same behavior as 'x'. - * 'c' Open the file for writing only. If the file does not exist, it is created. If it exists, it is neither truncated - * (as opposed to 'w'), nor the call to this function fails (as is the case with 'x'). The file pointer - * is positioned on the beginning of the file. - * This may be useful if it's desired to get an advisory lock (see flock()) before attempting to modify the file - * as using 'w' could truncate the file before the lock was obtained (if truncation is desired, ftruncate() can - * be used after the lock is requested). - * 'c+' Open the file for reading and writing; otherwise it has the same behavior as 'c'. - */ -static int StrModeToFlags(jx9_context *pCtx, const char *zMode, int nLen) -{ - const char *zEnd = &zMode[nLen]; - int iFlag = 0; - int c; - if( nLen < 1 ){ - /* Open in a read-only mode */ - return JX9_IO_OPEN_RDONLY; - } - c = zMode[0]; - if( c == 'r' || c == 'R' ){ - /* Read-only access */ - iFlag = JX9_IO_OPEN_RDONLY; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' || c == 'w' || c == 'W' ){ - /* Read+Write access */ - iFlag = JX9_IO_OPEN_RDWR; - } - } - }else if( c == 'w' || c == 'W' ){ - /* Overwrite mode. - * If the file does not exists, try to create it - */ - iFlag = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_TRUNC|JX9_IO_OPEN_CREATE; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' || c == 'r' || c == 'R' ){ - /* Read+Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_IO_OPEN_RDWR; - } - } - }else if( c == 'a' || c == 'A' ){ - /* Append mode (place the file pointer at the end of the file). - * Create the file if it does not exists. - */ - iFlag = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_APPEND|JX9_IO_OPEN_CREATE; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' ){ - /* Read-Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_IO_OPEN_RDWR; - } - } - }else if( c == 'x' || c == 'X' ){ - /* Exclusive access. - * If the file already exists, return immediately with a failure code. - * Otherwise create a new file. - */ - iFlag = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_EXCL; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' || c == 'r' || c == 'R' ){ - /* Read-Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_IO_OPEN_RDWR; - } - } - }else if( c == 'c' || c == 'C' ){ - /* Overwrite mode.Create the file if it does not exists.*/ - iFlag = JX9_IO_OPEN_WRONLY|JX9_IO_OPEN_CREATE; - zMode++; /* Advance */ - if( zMode < zEnd ){ - c = zMode[0]; - if( c == '+' ){ - /* Read-Write access */ - iFlag &= ~JX9_IO_OPEN_WRONLY; - iFlag |= JX9_IO_OPEN_RDWR; - } - } - }else{ - /* Invalid mode. Assume a read only open */ - jx9_context_throw_error(pCtx, JX9_CTX_NOTICE, "Invalid open mode, JX9 is assuming a Read-Only open"); - iFlag = JX9_IO_OPEN_RDONLY; - } - while( zMode < zEnd ){ - c = zMode[0]; - if( c == 'b' || c == 'B' ){ - iFlag &= ~JX9_IO_OPEN_TEXT; - iFlag |= JX9_IO_OPEN_BINARY; - }else if( c == 't' || c == 'T' ){ - iFlag &= ~JX9_IO_OPEN_BINARY; - iFlag |= JX9_IO_OPEN_TEXT; - } - zMode++; - } - return iFlag; -} -/* - * Initialize the IO private structure. - */ -static void InitIOPrivate(jx9_vm *pVm, const jx9_io_stream *pStream, io_private *pOut) -{ - pOut->pStream = pStream; - SyBlobInit(&pOut->sBuffer, &pVm->sAllocator); - pOut->nOfft = 0; - /* Set the magic number */ - pOut->iMagic = IO_PRIVATE_MAGIC; -} -/* - * Release the IO private structure. - */ -static void ReleaseIOPrivate(jx9_context *pCtx, io_private *pDev) -{ - SyBlobRelease(&pDev->sBuffer); - pDev->iMagic = 0x2126; /* Invalid magic number so we can detetct misuse */ - /* Release the whole structure */ - jx9_context_free_chunk(pCtx, pDev); -} -/* - * Reset the IO private structure. - */ -static void ResetIOPrivate(io_private *pDev) -{ - SyBlobReset(&pDev->sBuffer); - pDev->nOfft = 0; -} -/* Forward declaration */ -static int is_jx9_stream(const jx9_io_stream *pStream); -/* - * resource fopen(string $filename, string $mode [, bool $use_include_path = false[, resource $context ]]) - * Open a file, a URL or any other IO stream. - * Parameters - * $filename - * If filename is of the form "scheme://...", it is assumed to be a URL and JX9 will search - * for a protocol handler (also known as a wrapper) for that scheme. If no scheme is given - * then a regular file is assumed. - * $mode - * The mode parameter specifies the type of access you require to the stream - * See the block comment associated with the StrModeToFlags() for the supported - * modes. - * $use_include_path - * You can use the optional second parameter and set it to - * TRUE, if you want to search for the file in the include_path, too. - * $context - * A context stream resource. - * Return - * File handle on success or FALSE on failure. - */ -static int jx9Builtin_fopen(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zUri, *zMode; - jx9_value *pResource; - io_private *pDev; - int iLen, imLen; - int iOpenFlags; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path or URL"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the URI and the desired access mode */ - zUri = jx9_value_to_string(apArg[0], &iLen); - if( nArg > 1 ){ - zMode = jx9_value_to_string(apArg[1], &imLen); - }else{ - /* Set a default read-only mode */ - zMode = "r"; - imLen = (int)sizeof(char); - } - /* Try to extract a stream */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zUri, iLen); - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "No stream device is associated with the given URI(%s)", zUri); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Allocate a new IO private instance */ - pDev = (io_private *)jx9_context_alloc_chunk(pCtx, sizeof(io_private), TRUE, FALSE); - if( pDev == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pResource = 0; - if( nArg > 3 ){ - pResource = apArg[3]; - }else if( is_jx9_stream(pStream) ){ - /* TICKET 1433-80: The jx9:// stream need a jx9_value to access the underlying - * virtual machine. - */ - pResource = apArg[0]; - } - /* Initialize the structure */ - InitIOPrivate(pCtx->pVm, pStream, pDev); - /* Convert open mode to JX9 flags */ - iOpenFlags = StrModeToFlags(pCtx, zMode, imLen); - /* Try to get a handle */ - pDev->pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zUri, iOpenFlags, - nArg > 2 ? jx9_value_to_bool(apArg[2]) : FALSE, pResource, FALSE, 0); - if( pDev->pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zUri); - jx9_result_bool(pCtx, 0); - jx9_context_free_chunk(pCtx, pDev); - return JX9_OK; - } - /* All done, return the io_private instance as a resource */ - jx9_result_resource(pCtx, pDev); - return JX9_OK; -} -/* - * bool fclose(resource $handle) - * Closes an open file pointer - * Parameters - * $handle - * The file pointer. - * Return - * TRUE on success or FALSE on failure. - */ -static int jx9Builtin_fclose(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - io_private *pDev; - jx9_vm *pVm; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract our private data */ - pDev = (io_private *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid io_private instance */ - if( IO_PRIVATE_INVALID(pDev) ){ - /*Expecting an IO handle */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting an IO handle"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the target IO stream device */ - pStream = pDev->pStream; - if( pStream == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, - "IO routine(%s) not implemented in the underlying stream(%s) device, JX9 is returning FALSE", - jx9_function_name(pCtx), pStream ? pStream->zName : "null_stream" - ); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the VM that own this context */ - pVm = pCtx->pVm; - /* TICKET 1433-62: Keep the STDIN/STDOUT/STDERR handles open */ - if( pDev != pVm->pStdin && pDev != pVm->pStdout && pDev != pVm->pStderr ){ - /* Perform the requested operation */ - jx9StreamCloseHandle(pStream, pDev->pHandle); - /* Release the IO private structure */ - ReleaseIOPrivate(pCtx, pDev); - /* Invalidate the resource handle */ - jx9_value_release(apArg[0]); - } - /* Return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -#if !defined(JX9_DISABLE_HASH_FUNC) -/* - * MD5/SHA1 digest consumer. - */ -static int vfsHashConsumer(const void *pData, unsigned int nLen, void *pUserData) -{ - /* Append hex chunk verbatim */ - jx9_result_string((jx9_context *)pUserData, (const char *)pData, (int)nLen); - return SXRET_OK; -} -/* - * string md5_file(string $uri[, bool $raw_output = false ]) - * Calculates the md5 hash of a given file. - * Parameters - * $uri - * Target URI (file(/path/to/something) or URL(http://www.symisc.net/)) - * $raw_output - * When TRUE, returns the digest in raw binary format with a length of 16. - * Return - * Return the MD5 digest on success or FALSE on failure. - */ -static int jx9Builtin_md5_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - unsigned char zDigest[16]; - int raw_output = FALSE; - const char *zFile; - MD5Context sCtx; - char zBuf[8192]; - void *pHandle; - jx9_int64 n; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 1 ){ - raw_output = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Init the MD5 context */ - MD5Init(&sCtx); - /* Perform the requested operation */ - for(;;){ - n = pStream->xRead(pHandle, zBuf, sizeof(zBuf)); - if( n < 1 ){ - /* EOF or IO error, break immediately */ - break; - } - MD5Update(&sCtx, (const unsigned char *)zBuf, (unsigned int)n); - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Extract the digest */ - MD5Final(zDigest, &sCtx); - if( raw_output ){ - /* Output raw digest */ - jx9_result_string(pCtx, (const char *)zDigest, sizeof(zDigest)); - }else{ - /* Perform a binary to hex conversion */ - SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), vfsHashConsumer, pCtx); - } - return JX9_OK; -} -/* - * string sha1_file(string $uri[, bool $raw_output = false ]) - * Calculates the SHA1 hash of a given file. - * Parameters - * $uri - * Target URI (file(/path/to/something) or URL(http://www.symisc.net/)) - * $raw_output - * When TRUE, returns the digest in raw binary format with a length of 20. - * Return - * Return the SHA1 digest on success or FALSE on failure. - */ -static int jx9Builtin_sha1_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - unsigned char zDigest[20]; - int raw_output = FALSE; - const char *zFile; - SHA1Context sCtx; - char zBuf[8192]; - void *pHandle; - jx9_int64 n; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 1 ){ - raw_output = jx9_value_to_bool(apArg[1]); - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Init the SHA1 context */ - SHA1Init(&sCtx); - /* Perform the requested operation */ - for(;;){ - n = pStream->xRead(pHandle, zBuf, sizeof(zBuf)); - if( n < 1 ){ - /* EOF or IO error, break immediately */ - break; - } - SHA1Update(&sCtx, (const unsigned char *)zBuf, (unsigned int)n); - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Extract the digest */ - SHA1Final(&sCtx, zDigest); - if( raw_output ){ - /* Output raw digest */ - jx9_result_string(pCtx, (const char *)zDigest, sizeof(zDigest)); - }else{ - /* Perform a binary to hex conversion */ - SyBinToHexConsumer((const void *)zDigest, sizeof(zDigest), vfsHashConsumer, pCtx); - } - return JX9_OK; -} -#endif /* JX9_DISABLE_HASH_FUNC */ -/* - * array parse_ini_file(string $filename[, bool $process_sections = false [, int $scanner_mode = INI_SCANNER_NORMAL ]] ) - * Parse a configuration file. - * Parameters - * $filename - * The filename of the ini file being parsed. - * $process_sections - * By setting the process_sections parameter to TRUE, you get a multidimensional array - * with the section names and settings included. - * The default for process_sections is FALSE. - * $scanner_mode - * Can either be INI_SCANNER_NORMAL (default) or INI_SCANNER_RAW. - * If INI_SCANNER_RAW is supplied, then option values will not be parsed. - * Return - * The settings are returned as an associative array on success. - * Otherwise is returned. - */ -static int jx9Builtin_parse_ini_file(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - const char *zFile; - SyBlob sContents; - void *pHandle; - int nLen; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - SyBlobInit(&sContents, &pCtx->pVm->sAllocator); - /* Read the whole file */ - jx9StreamReadWholeFile(pHandle, pStream, &sContents); - if( SyBlobLength(&sContents) < 1 ){ - /* Empty buffer, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Process the raw INI buffer */ - jx9ParseIniString(pCtx, (const char *)SyBlobData(&sContents), SyBlobLength(&sContents), - nArg > 1 ? jx9_value_to_bool(apArg[1]) : 0); - } - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - /* Release the working buffer */ - SyBlobRelease(&sContents); - return JX9_OK; -} -/* - * Section: - * ZIP archive processing. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -typedef struct zip_raw_data zip_raw_data; -struct zip_raw_data -{ - int iType; /* Where the raw data is stored */ - union raw_data{ - struct mmap_data{ - void *pMap; /* Memory mapped data */ - jx9_int64 nSize; /* Map size */ - const jx9_vfs *pVfs; /* Underlying vfs */ - }mmap; - SyBlob sBlob; /* Memory buffer */ - }raw; -}; -#define ZIP_RAW_DATA_MMAPED 1 /* Memory mapped ZIP raw data */ -#define ZIP_RAW_DATA_MEMBUF 2 /* ZIP raw data stored in a dynamically - * allocated memory chunk. - */ - /* - * mixed zip_open(string $filename) - * Opens a new zip archive for reading. - * Parameters - * $filename - * The file name of the ZIP archive to open. - * Return - * A resource handle for later use with zip_read() and zip_close() or FALSE on failure. - */ -static int jx9Builtin_zip_open(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const jx9_io_stream *pStream; - SyArchive *pArchive; - zip_raw_data *pRaw; - const char *zFile; - SyBlob *pContents; - void *pHandle; - int nLen; - sxi32 rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Expecting a file path"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the file path */ - zFile = jx9_value_to_string(apArg[0], &nLen); - /* Point to the target IO stream device */ - pStream = jx9VmGetStreamDevice(pCtx->pVm, &zFile, nLen); - if( pStream == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "No such stream device, JX9 is returning FALSE"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Create an in-memory archive */ - pArchive = (SyArchive *)jx9_context_alloc_chunk(pCtx, sizeof(SyArchive)+sizeof(zip_raw_data), TRUE, FALSE); - if( pArchive == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pRaw = (zip_raw_data *)&pArchive[1]; - /* Initialize the archive */ - SyArchiveInit(pArchive, &pCtx->pVm->sAllocator, 0, 0); - /* Extract the default stream */ - if( pStream == pCtx->pVm->pDefStream /* file:// stream*/){ - const jx9_vfs *pVfs; - /* Try to get a memory view of the whole file since ZIP files - * tends to be very big this days, this is a huge performance win. - */ - pVfs = jx9ExportBuiltinVfs(); - if( pVfs && pVfs->xMmap ){ - rc = pVfs->xMmap(zFile, &pRaw->raw.mmap.pMap, &pRaw->raw.mmap.nSize); - if( rc == JX9_OK ){ - /* Nice, Extract the whole archive */ - rc = SyZipExtractFromBuf(pArchive, (const char *)pRaw->raw.mmap.pMap, (sxu32)pRaw->raw.mmap.nSize); - if( rc != SXRET_OK ){ - if( pVfs->xUnmap ){ - pVfs->xUnmap(pRaw->raw.mmap.pMap, pRaw->raw.mmap.nSize); - } - /* Release the allocated chunk */ - jx9_context_free_chunk(pCtx, pArchive); - /* Something goes wrong with this ZIP archive, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Archive successfully opened */ - pRaw->iType = ZIP_RAW_DATA_MMAPED; - pRaw->raw.mmap.pVfs = pVfs; - goto success; - } - } - /* FALL THROUGH */ - } - /* Try to open the file in read-only mode */ - pHandle = jx9StreamOpenHandle(pCtx->pVm, pStream, zFile, JX9_IO_OPEN_RDONLY, FALSE, 0, FALSE, 0); - if( pHandle == 0 ){ - jx9_context_throw_error_format(pCtx, JX9_CTX_ERR, "IO error while opening '%s'", zFile); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - pContents = &pRaw->raw.sBlob; - SyBlobInit(pContents, &pCtx->pVm->sAllocator); - /* Read the whole file */ - jx9StreamReadWholeFile(pHandle, pStream, pContents); - /* Assume an invalid ZIP file */ - rc = SXERR_INVALID; - if( SyBlobLength(pContents) > 0 ){ - /* Extract archive entries */ - rc = SyZipExtractFromBuf(pArchive, (const char *)SyBlobData(pContents), SyBlobLength(pContents)); - } - pRaw->iType = ZIP_RAW_DATA_MEMBUF; - /* Close the stream */ - jx9StreamCloseHandle(pStream, pHandle); - if( rc != SXRET_OK ){ - /* Release the working buffer */ - SyBlobRelease(pContents); - /* Release the allocated chunk */ - jx9_context_free_chunk(pCtx, pArchive); - /* Something goes wrong with this ZIP archive, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } -success: - /* Reset the loop cursor */ - SyArchiveResetLoopCursor(pArchive); - /* Return the in-memory archive as a resource handle */ - jx9_result_resource(pCtx, pArchive); - return JX9_OK; -} -/* - * void zip_close(resource $zip) - * Close an in-memory ZIP archive. - * Parameters - * $zip - * A ZIP file previously opened with zip_open(). - * Return - * null. - */ -static int jx9Builtin_zip_close(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchive *pArchive; - zip_raw_data *pRaw; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - return JX9_OK; - } - /* Point to the in-memory archive */ - pArchive = (SyArchive *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid ZIP archive */ - if( SXARCH_INVALID(pArchive) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - return JX9_OK; - } - /* Release the archive */ - SyArchiveRelease(pArchive); - pRaw = (zip_raw_data *)&pArchive[1]; - if( pRaw->iType == ZIP_RAW_DATA_MEMBUF ){ - SyBlobRelease(&pRaw->raw.sBlob); - }else{ - const jx9_vfs *pVfs = pRaw->raw.mmap.pVfs; - if( pVfs->xUnmap ){ - /* Unmap the memory view */ - pVfs->xUnmap(pRaw->raw.mmap.pMap, pRaw->raw.mmap.nSize); - } - } - /* Release the memory chunk */ - jx9_context_free_chunk(pCtx, pArchive); - return JX9_OK; -} -/* - * mixed zip_read(resource $zip) - * Reads the next entry from an in-memory ZIP archive. - * Parameters - * $zip - * A ZIP file previously opened with zip_open(). - * Return - * A directory entry resource for later use with the zip_entry_... functions - * or FALSE if there are no more entries to read, or an error code if an error occurred. - */ -static int jx9Builtin_zip_read(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pNext = 0; /* cc warning */ - SyArchive *pArchive; - sxi32 rc; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the in-memory archive */ - pArchive = (SyArchive *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid ZIP archive */ - if( SXARCH_INVALID(pArchive) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the next entry */ - rc = SyArchiveGetNextEntry(pArchive, &pNext); - if( rc != SXRET_OK ){ - /* No more entries in the central directory, return FALSE */ - jx9_result_bool(pCtx, 0); - }else{ - /* Return as a resource handle */ - jx9_result_resource(pCtx, pNext); - /* Point to the ZIP raw data */ - pNext->pUserData = (void *)&pArchive[1]; - } - return JX9_OK; -} -/* - * bool zip_entry_open(resource $zip, resource $zip_entry[, string $mode ]) - * Open a directory entry for reading - * Parameters - * $zip - * A ZIP file previously opened with zip_open(). - * $zip_entry - * A directory entry returned by zip_read(). - * $mode - * Not used - * Return - * A directory entry resource for later use with the zip_entry_... functions - * or FALSE if there are no more entries to read, or an error code if an error occurred. - */ -static int jx9Builtin_zip_entry_open(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - SyArchive *pArchive; - if( nArg < 2 || !jx9_value_is_resource(apArg[0]) || !jx9_value_is_resource(apArg[1]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Point to the in-memory archive */ - pArchive = (SyArchive *)jx9_value_to_resource(apArg[0]); - /* Make sure we are dealing with a valid ZIP archive */ - if( SXARCH_INVALID(pArchive) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[1]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* All done. Actually this function is a no-op, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * bool zip_entry_close(resource $zip_entry) - * Close a directory entry. - * Parameters - * $zip_entry - * A directory entry returned by zip_read(). - * Return - * Returns TRUE on success or FALSE on failure. - */ -static int jx9Builtin_zip_entry_close(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Reset the read cursor */ - pEntry->nReadCount = 0; - /*All done. Actually this function is a no-op, return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * string zip_entry_name(resource $zip_entry) - * Retrieve the name of a directory entry. - * Parameters - * $zip_entry - * A directory entry returned by zip_read(). - * Return - * The name of the directory entry. - */ -static int jx9Builtin_zip_entry_name(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - SyString *pName; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return entry name */ - pName = &pEntry->sFileName; - jx9_result_string(pCtx, pName->zString, (int)pName->nByte); - return JX9_OK; -} -/* - * int64 zip_entry_filesize(resource $zip_entry) - * Retrieve the actual file size of a directory entry. - * Parameters - * $zip_entry - * A directory entry returned by zip_read(). - * Return - * The size of the directory entry. - */ -static int jx9Builtin_zip_entry_filesize(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return entry size */ - jx9_result_int64(pCtx, (jx9_int64)pEntry->nByte); - return JX9_OK; -} -/* - * int64 zip_entry_compressedsize(resource $zip_entry) - * Retrieve the compressed size of a directory entry. - * Parameters - * $zip_entry - * A directory entry returned by zip_read(). - * Return - * The compressed size. - */ -static int jx9Builtin_zip_entry_compressedsize(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Return entry compressed size */ - jx9_result_int64(pCtx, (jx9_int64)pEntry->nByteCompr); - return JX9_OK; -} -/* - * string zip_entry_read(resource $zip_entry[, int $length]) - * Reads from an open directory entry. - * Parameters - * $zip_entry - * A directory entry returned by zip_read(). - * $length - * The number of bytes to return. If not specified, this function - * will attempt to read 1024 bytes. - * Return - * Returns the data read, or FALSE if the end of the file is reached. - */ -static int jx9Builtin_zip_entry_read(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - zip_raw_data *pRaw; - const char *zData; - int iLength; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - zData = 0; - if( pEntry->nReadCount >= pEntry->nByteCompr ){ - /* No more data to read, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Set a default read length */ - iLength = 1024; - if( nArg > 1 ){ - iLength = jx9_value_to_int(apArg[1]); - if( iLength < 1 ){ - iLength = 1024; - } - } - if( (sxu32)iLength > pEntry->nByteCompr - pEntry->nReadCount ){ - iLength = (int)(pEntry->nByteCompr - pEntry->nReadCount); - } - /* Return the entry contents */ - pRaw = (zip_raw_data *)pEntry->pUserData; - if( pRaw->iType == ZIP_RAW_DATA_MEMBUF ){ - zData = (const char *)SyBlobDataAt(&pRaw->raw.sBlob, (pEntry->nOfft+pEntry->nReadCount)); - }else{ - const char *zMap = (const char *)pRaw->raw.mmap.pMap; - /* Memory mmaped chunk */ - zData = &zMap[pEntry->nOfft+pEntry->nReadCount]; - } - /* Increment the read counter */ - pEntry->nReadCount += iLength; - /* Return the raw data */ - jx9_result_string(pCtx, zData, iLength); - return JX9_OK; -} -/* - * bool zip_entry_reset_cursor(resource $zip_entry) - * Reset the read cursor of an open directory entry. - * Parameters - * $zip_entry - * A directory entry returned by zip_read(). - * Return - * TRUE on success, FALSE on failure. - */ -static int jx9Builtin_zip_entry_reset_cursor(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Reset the cursor */ - pEntry->nReadCount = 0; - /* Return TRUE */ - jx9_result_bool(pCtx, 1); - return JX9_OK; -} -/* - * string zip_entry_compressionmethod(resource $zip_entry) - * Retrieve the compression method of a directory entry. - * Parameters - * $zip_entry - * A directory entry returned by zip_read(). - * Return - * The compression method on success or FALSE on failure. - */ -static int jx9Builtin_zip_entry_compressionmethod(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyArchiveEntry *pEntry; - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Make sure we are dealing with a valid ZIP archive entry */ - pEntry = (SyArchiveEntry *)jx9_value_to_resource(apArg[0]); - if( SXARCH_ENTRY_INVALID(pEntry) ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Expecting a ZIP archive entry"); - /* return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - switch(pEntry->nComprMeth){ - case 0: - /* No compression;entry is stored */ - jx9_result_string(pCtx, "stored", (int)sizeof("stored")-1); - break; - case 8: - /* Entry is deflated (Default compression algorithm) */ - jx9_result_string(pCtx, "deflate", (int)sizeof("deflate")-1); - break; - /* Exotic compression algorithms */ - case 1: - jx9_result_string(pCtx, "shrunk", (int)sizeof("shrunk")-1); - break; - case 2: - case 3: - case 4: - case 5: - /* Entry is reduced */ - jx9_result_string(pCtx, "reduced", (int)sizeof("reduced")-1); - break; - case 6: - /* Entry is imploded */ - jx9_result_string(pCtx, "implode", (int)sizeof("implode")-1); - break; - default: - jx9_result_string(pCtx, "unknown", (int)sizeof("unknown")-1); - break; - } - return JX9_OK; -} -#endif /* #ifndef JX9_DISABLE_BUILTIN_FUNC*/ -/* NULL VFS [i.e: a no-op VFS]*/ -static const jx9_vfs null_vfs = { - "null_vfs", - JX9_VFS_VERSION, - 0, /* int (*xChdir)(const char *) */ - 0, /* int (*xChroot)(const char *); */ - 0, /* int (*xGetcwd)(jx9_context *) */ - 0, /* int (*xMkdir)(const char *, int, int) */ - 0, /* int (*xRmdir)(const char *) */ - 0, /* int (*xIsdir)(const char *) */ - 0, /* int (*xRename)(const char *, const char *) */ - 0, /*int (*xRealpath)(const char *, jx9_context *)*/ - 0, /* int (*xSleep)(unsigned int) */ - 0, /* int (*xUnlink)(const char *) */ - 0, /* int (*xFileExists)(const char *) */ - 0, /*int (*xChmod)(const char *, int)*/ - 0, /*int (*xChown)(const char *, const char *)*/ - 0, /*int (*xChgrp)(const char *, const char *)*/ - 0, /* jx9_int64 (*xFreeSpace)(const char *) */ - 0, /* jx9_int64 (*xTotalSpace)(const char *) */ - 0, /* jx9_int64 (*xFileSize)(const char *) */ - 0, /* jx9_int64 (*xFileAtime)(const char *) */ - 0, /* jx9_int64 (*xFileMtime)(const char *) */ - 0, /* jx9_int64 (*xFileCtime)(const char *) */ - 0, /* int (*xStat)(const char *, jx9_value *, jx9_value *) */ - 0, /* int (*xlStat)(const char *, jx9_value *, jx9_value *) */ - 0, /* int (*xIsfile)(const char *) */ - 0, /* int (*xIslink)(const char *) */ - 0, /* int (*xReadable)(const char *) */ - 0, /* int (*xWritable)(const char *) */ - 0, /* int (*xExecutable)(const char *) */ - 0, /* int (*xFiletype)(const char *, jx9_context *) */ - 0, /* int (*xGetenv)(const char *, jx9_context *) */ - 0, /* int (*xSetenv)(const char *, const char *) */ - 0, /* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ - 0, /* int (*xMmap)(const char *, void **, jx9_int64 *) */ - 0, /* void (*xUnmap)(void *, jx9_int64); */ - 0, /* int (*xLink)(const char *, const char *, int) */ - 0, /* int (*xUmask)(int) */ - 0, /* void (*xTempDir)(jx9_context *) */ - 0, /* unsigned int (*xProcessId)(void) */ - 0, /* int (*xUid)(void) */ - 0, /* int (*xGid)(void) */ - 0, /* void (*xUsername)(jx9_context *) */ - 0 /* int (*xExec)(const char *, jx9_context *) */ -}; -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_DISK_IO -#ifdef __WINNT__ -/* - * Windows VFS implementation for the JX9 engine. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* What follows here is code that is specific to windows systems. */ -#include -/* -** Convert a UTF-8 string to microsoft unicode (UTF-16?). -** -** Space to hold the returned string is obtained from HeapAlloc(). -** Taken from the sqlite3 source tree -** status: Public Domain -*/ -static WCHAR *jx9utf8ToUnicode(const char *zFilename){ - int nChar; - WCHAR *zWideFilename; - - nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, 0, 0); - zWideFilename = (WCHAR *)HeapAlloc(GetProcessHeap(), 0, nChar*sizeof(zWideFilename[0])); - if( zWideFilename == 0 ){ - return 0; - } - nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); - if( nChar==0 ){ - HeapFree(GetProcessHeap(), 0, zWideFilename); - return 0; - } - return zWideFilename; -} -/* -** Convert a UTF-8 filename into whatever form the underlying -** operating system wants filenames in.Space to hold the result -** is obtained from HeapAlloc() and must be freed by the calling -** function. -** Taken from the sqlite3 source tree -** status: Public Domain -*/ -static void *jx9convertUtf8Filename(const char *zFilename){ - void *zConverted; - zConverted = jx9utf8ToUnicode(zFilename); - return zConverted; -} -/* -** Convert microsoft unicode to UTF-8. Space to hold the returned string is -** obtained from HeapAlloc(). -** Taken from the sqlite3 source tree -** status: Public Domain -*/ -static char *jx9unicodeToUtf8(const WCHAR *zWideFilename){ - char *zFilename; - int nByte; - - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); - zFilename = (char *)HeapAlloc(GetProcessHeap(), 0, nByte); - if( zFilename == 0 ){ - return 0; - } - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, 0, 0); - if( nByte == 0 ){ - HeapFree(GetProcessHeap(), 0, zFilename); - return 0; - } - return zFilename; -} -/* int (*xchdir)(const char *) */ -static int WinVfs_chdir(const char *zPath) -{ - void * pConverted; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - rc = SetCurrentDirectoryW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : -1; -} -/* int (*xGetcwd)(jx9_context *) */ -static int WinVfs_getcwd(jx9_context *pCtx) -{ - WCHAR zDir[2048]; - char *zConverted; - DWORD rc; - /* Get the current directory */ - rc = GetCurrentDirectoryW(sizeof(zDir), zDir); - if( rc < 1 ){ - return -1; - } - zConverted = jx9unicodeToUtf8(zDir); - if( zConverted == 0 ){ - return -1; - } - jx9_result_string(pCtx, zConverted, -1/*Compute length automatically*/); /* Will make it's own copy */ - HeapFree(GetProcessHeap(), 0, zConverted); - return JX9_OK; -} -/* int (*xMkdir)(const char *, int, int) */ -static int WinVfs_mkdir(const char *zPath, int mode, int recursive) -{ - void * pConverted; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - mode= 0; /* MSVC warning */ - recursive = 0; - rc = CreateDirectoryW((LPCWSTR)pConverted, 0); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : -1; -} -/* int (*xRmdir)(const char *) */ -static int WinVfs_rmdir(const char *zPath) -{ - void * pConverted; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - rc = RemoveDirectoryW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : -1; -} -/* int (*xIsdir)(const char *) */ -static int WinVfs_isdir(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - return -1; - } - return (dwAttr & FILE_ATTRIBUTE_DIRECTORY) ? JX9_OK : -1; -} -/* int (*xRename)(const char *, const char *) */ -static int WinVfs_Rename(const char *zOld, const char *zNew) -{ - void *pOld, *pNew; - BOOL rc = 0; - pOld = jx9convertUtf8Filename(zOld); - if( pOld == 0 ){ - return -1; - } - pNew = jx9convertUtf8Filename(zNew); - if( pNew ){ - rc = MoveFileW((LPCWSTR)pOld, (LPCWSTR)pNew); - } - HeapFree(GetProcessHeap(), 0, pOld); - if( pNew ){ - HeapFree(GetProcessHeap(), 0, pNew); - } - return rc ? JX9_OK : - 1; -} -/* int (*xRealpath)(const char *, jx9_context *) */ -static int WinVfs_Realpath(const char *zPath, jx9_context *pCtx) -{ - WCHAR zTemp[2048]; - void *pPath; - char *zReal; - DWORD n; - pPath = jx9convertUtf8Filename(zPath); - if( pPath == 0 ){ - return -1; - } - n = GetFullPathNameW((LPCWSTR)pPath, 0, 0, 0); - if( n > 0 ){ - if( n >= sizeof(zTemp) ){ - n = sizeof(zTemp) - 1; - } - GetFullPathNameW((LPCWSTR)pPath, n, zTemp, 0); - } - HeapFree(GetProcessHeap(), 0, pPath); - if( !n ){ - return -1; - } - zReal = jx9unicodeToUtf8(zTemp); - if( zReal == 0 ){ - return -1; - } - jx9_result_string(pCtx, zReal, -1); /* Will make it's own copy */ - HeapFree(GetProcessHeap(), 0, zReal); - return JX9_OK; -} -/* int (*xSleep)(unsigned int) */ -static int WinVfs_Sleep(unsigned int uSec) -{ - Sleep(uSec/1000/*uSec per Millisec */); - return JX9_OK; -} -/* int (*xUnlink)(const char *) */ -static int WinVfs_unlink(const char *zPath) -{ - void * pConverted; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - rc = DeleteFileW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : - 1; -} -/* jx9_int64 (*xFreeSpace)(const char *) */ -static jx9_int64 WinVfs_DiskFreeSpace(const char *zPath) -{ -#ifdef _WIN32_WCE - /* GetDiskFreeSpace is not supported under WINCE */ - SXUNUSED(zPath); - return 0; -#else - DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters; - void * pConverted; - WCHAR *p; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return 0; - } - p = (WCHAR *)pConverted; - for(;*p;p++){ - if( *p == '\\' || *p == '/'){ - *p = '\0'; - break; - } - } - rc = GetDiskFreeSpaceW((LPCWSTR)pConverted, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); - if( !rc ){ - return 0; - } - return (jx9_int64)dwFreeClusters * dwSectPerClust * dwBytesPerSect; -#endif -} -/* jx9_int64 (*xTotalSpace)(const char *) */ -static jx9_int64 WinVfs_DiskTotalSpace(const char *zPath) -{ -#ifdef _WIN32_WCE - /* GetDiskFreeSpace is not supported under WINCE */ - SXUNUSED(zPath); - return 0; -#else - DWORD dwSectPerClust, dwBytesPerSect, dwFreeClusters, dwTotalClusters; - void * pConverted; - WCHAR *p; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return 0; - } - p = (WCHAR *)pConverted; - for(;*p;p++){ - if( *p == '\\' || *p == '/'){ - *p = '\0'; - break; - } - } - rc = GetDiskFreeSpaceW((LPCWSTR)pConverted, &dwSectPerClust, &dwBytesPerSect, &dwFreeClusters, &dwTotalClusters); - if( !rc ){ - return 0; - } - return (jx9_int64)dwTotalClusters * dwSectPerClust * dwBytesPerSect; -#endif -} -/* int (*xFileExists)(const char *) */ -static int WinVfs_FileExists(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - return -1; - } - return JX9_OK; -} -/* Open a file in a read-only mode */ -static HANDLE OpenReadOnly(LPCWSTR pPath) -{ - DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; - DWORD dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE; - DWORD dwAccess = GENERIC_READ; - DWORD dwCreate = OPEN_EXISTING; - HANDLE pHandle; - pHandle = CreateFileW(pPath, dwAccess, dwShare, 0, dwCreate, dwType, 0); - if( pHandle == INVALID_HANDLE_VALUE){ - return 0; - } - return pHandle; -} -/* jx9_int64 (*xFileSize)(const char *) */ -static jx9_int64 WinVfs_FileSize(const char *zPath) -{ - DWORD dwLow, dwHigh; - void * pConverted; - jx9_int64 nSize; - HANDLE pHandle; - - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - /* Open the file in read-only mode */ - pHandle = OpenReadOnly((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( pHandle ){ - dwLow = GetFileSize(pHandle, &dwHigh); - nSize = dwHigh; - nSize <<= 32; - nSize += dwLow; - CloseHandle(pHandle); - }else{ - nSize = -1; - } - return nSize; -} -#define TICKS_PER_SECOND 10000000 -#define EPOCH_DIFFERENCE 11644473600LL -/* Convert Windows timestamp to UNIX timestamp */ -static jx9_int64 convertWindowsTimeToUnixTime(LPFILETIME pTime) -{ - jx9_int64 input, temp; - input = pTime->dwHighDateTime; - input <<= 32; - input += pTime->dwLowDateTime; - temp = input / TICKS_PER_SECOND; /*convert from 100ns intervals to seconds*/ - temp = temp - EPOCH_DIFFERENCE; /*subtract number of seconds between epochs*/ - return temp; -} -/* Convert UNIX timestamp to Windows timestamp */ -static void convertUnixTimeToWindowsTime(jx9_int64 nUnixtime, LPFILETIME pOut) -{ - jx9_int64 result = EPOCH_DIFFERENCE; - result += nUnixtime; - result *= 10000000LL; - pOut->dwHighDateTime = (DWORD)(nUnixtime>>32); - pOut->dwLowDateTime = (DWORD)nUnixtime; -} -/* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ -static int WinVfs_Touch(const char *zPath, jx9_int64 touch_time, jx9_int64 access_time) -{ - FILETIME sTouch, sAccess; - void *pConverted; - void *pHandle; - BOOL rc = 0; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - pHandle = OpenReadOnly((LPCWSTR)pConverted); - if( pHandle ){ - if( touch_time < 0 ){ - GetSystemTimeAsFileTime(&sTouch); - }else{ - convertUnixTimeToWindowsTime(touch_time, &sTouch); - } - if( access_time < 0 ){ - /* Use the touch time */ - sAccess = sTouch; /* Structure assignment */ - }else{ - convertUnixTimeToWindowsTime(access_time, &sAccess); - } - rc = SetFileTime(pHandle, &sTouch, &sAccess, 0); - /* Close the handle */ - CloseHandle(pHandle); - } - HeapFree(GetProcessHeap(), 0, pConverted); - return rc ? JX9_OK : -1; -} -/* jx9_int64 (*xFileAtime)(const char *) */ -static jx9_int64 WinVfs_FileAtime(const char *zPath) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void * pConverted; - jx9_int64 atime; - HANDLE pHandle; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - /* Open the file in read-only mode */ - pHandle = OpenReadOnly((LPCWSTR)pConverted); - if( pHandle ){ - BOOL rc; - rc = GetFileInformationByHandle(pHandle, &sInfo); - if( rc ){ - atime = convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime); - }else{ - atime = -1; - } - CloseHandle(pHandle); - }else{ - atime = -1; - } - HeapFree(GetProcessHeap(), 0, pConverted); - return atime; -} -/* jx9_int64 (*xFileMtime)(const char *) */ -static jx9_int64 WinVfs_FileMtime(const char *zPath) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void * pConverted; - jx9_int64 mtime; - HANDLE pHandle; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - /* Open the file in read-only mode */ - pHandle = OpenReadOnly((LPCWSTR)pConverted); - if( pHandle ){ - BOOL rc; - rc = GetFileInformationByHandle(pHandle, &sInfo); - if( rc ){ - mtime = convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime); - }else{ - mtime = -1; - } - CloseHandle(pHandle); - }else{ - mtime = -1; - } - HeapFree(GetProcessHeap(), 0, pConverted); - return mtime; -} -/* jx9_int64 (*xFileCtime)(const char *) */ -static jx9_int64 WinVfs_FileCtime(const char *zPath) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void * pConverted; - jx9_int64 ctime; - HANDLE pHandle; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - /* Open the file in read-only mode */ - pHandle = OpenReadOnly((LPCWSTR)pConverted); - if( pHandle ){ - BOOL rc; - rc = GetFileInformationByHandle(pHandle, &sInfo); - if( rc ){ - ctime = convertWindowsTimeToUnixTime(&sInfo.ftCreationTime); - }else{ - ctime = -1; - } - CloseHandle(pHandle); - }else{ - ctime = -1; - } - HeapFree(GetProcessHeap(), 0, pConverted); - return ctime; -} -/* int (*xStat)(const char *, jx9_value *, jx9_value *) */ -/* int (*xlStat)(const char *, jx9_value *, jx9_value *) */ -static int WinVfs_Stat(const char *zPath, jx9_value *pArray, jx9_value *pWorker) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - void *pConverted; - HANDLE pHandle; - BOOL rc; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - /* Open the file in read-only mode */ - pHandle = OpenReadOnly((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( pHandle == 0 ){ - return -1; - } - rc = GetFileInformationByHandle(pHandle, &sInfo); - CloseHandle(pHandle); - if( !rc ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)sInfo.dwVolumeSerialNumber); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow)); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)sInfo.nNumberOfLinks); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow)); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime)); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime)); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftCreationTime)); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* int (*xIsfile)(const char *) */ -static int WinVfs_isfile(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - return -1; - } - return (dwAttr & (FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE)) ? JX9_OK : -1; -} -/* int (*xIslink)(const char *) */ -static int WinVfs_islink(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - return -1; - } - return (dwAttr & FILE_ATTRIBUTE_REPARSE_POINT) ? JX9_OK : -1; -} -/* int (*xWritable)(const char *) */ -static int WinVfs_iswritable(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - return -1; - } - if( (dwAttr & (FILE_ATTRIBUTE_ARCHIVE|FILE_ATTRIBUTE_NORMAL)) == 0 ){ - /* Not a regular file */ - return -1; - } - if( dwAttr & FILE_ATTRIBUTE_READONLY ){ - /* Read-only file */ - return -1; - } - /* File is writable */ - return JX9_OK; -} -/* int (*xExecutable)(const char *) */ -static int WinVfs_isexecutable(const char *zPath) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - return -1; - } - if( (dwAttr & FILE_ATTRIBUTE_NORMAL) == 0 ){ - /* Not a regular file */ - return -1; - } - /* File is executable */ - return JX9_OK; -} -/* int (*xFiletype)(const char *, jx9_context *) */ -static int WinVfs_Filetype(const char *zPath, jx9_context *pCtx) -{ - void * pConverted; - DWORD dwAttr; - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - /* Expand 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return -1; - } - dwAttr = GetFileAttributesW((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( dwAttr == INVALID_FILE_ATTRIBUTES ){ - /* Expand 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return -1; - } - if(dwAttr & (FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_NORMAL|FILE_ATTRIBUTE_ARCHIVE) ){ - jx9_result_string(pCtx, "file", sizeof("file")-1); - }else if(dwAttr & FILE_ATTRIBUTE_DIRECTORY){ - jx9_result_string(pCtx, "dir", sizeof("dir")-1); - }else if(dwAttr & FILE_ATTRIBUTE_REPARSE_POINT){ - jx9_result_string(pCtx, "link", sizeof("link")-1); - }else if(dwAttr & (FILE_ATTRIBUTE_DEVICE)){ - jx9_result_string(pCtx, "block", sizeof("block")-1); - }else{ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - } - return JX9_OK; -} -/* int (*xGetenv)(const char *, jx9_context *) */ -static int WinVfs_Getenv(const char *zVar, jx9_context *pCtx) -{ - char zValue[1024]; - DWORD n; - /* - * According to MSDN - * If lpBuffer is not large enough to hold the data, the return - * value is the buffer size, in characters, required to hold the - * string and its terminating null character and the contents - * of lpBuffer are undefined. - */ - n = sizeof(zValue); - SyMemcpy("Undefined", zValue, sizeof("Undefined")-1); - /* Extract the environment value */ - n = GetEnvironmentVariableA(zVar, zValue, sizeof(zValue)); - if( !n ){ - /* No such variable*/ - return -1; - } - jx9_result_string(pCtx, zValue, (int)n); - return JX9_OK; -} -/* int (*xSetenv)(const char *, const char *) */ -static int WinVfs_Setenv(const char *zName, const char *zValue) -{ - BOOL rc; - rc = SetEnvironmentVariableA(zName, zValue); - return rc ? JX9_OK : -1; -} -/* int (*xMmap)(const char *, void **, jx9_int64 *) */ -static int WinVfs_Mmap(const char *zPath, void **ppMap, jx9_int64 *pSize) -{ - DWORD dwSizeLow, dwSizeHigh; - HANDLE pHandle, pMapHandle; - void *pConverted, *pView; - - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - pHandle = OpenReadOnly((LPCWSTR)pConverted); - HeapFree(GetProcessHeap(), 0, pConverted); - if( pHandle == 0 ){ - return -1; - } - /* Get the file size */ - dwSizeLow = GetFileSize(pHandle, &dwSizeHigh); - /* Create the mapping */ - pMapHandle = CreateFileMappingW(pHandle, 0, PAGE_READONLY, dwSizeHigh, dwSizeLow, 0); - if( pMapHandle == 0 ){ - CloseHandle(pHandle); - return -1; - } - *pSize = ((jx9_int64)dwSizeHigh << 32) | dwSizeLow; - /* Obtain the view */ - pView = MapViewOfFile(pMapHandle, FILE_MAP_READ, 0, 0, (SIZE_T)(*pSize)); - if( pView ){ - /* Let the upper layer point to the view */ - *ppMap = pView; - } - /* Close the handle - * According to MSDN it's OK the close the HANDLES. - */ - CloseHandle(pMapHandle); - CloseHandle(pHandle); - return pView ? JX9_OK : -1; -} -/* void (*xUnmap)(void *, jx9_int64) */ -static void WinVfs_Unmap(void *pView, jx9_int64 nSize) -{ - nSize = 0; /* Compiler warning */ - UnmapViewOfFile(pView); -} -/* void (*xTempDir)(jx9_context *) */ -static void WinVfs_TempDir(jx9_context *pCtx) -{ - CHAR zTemp[1024]; - DWORD n; - n = GetTempPathA(sizeof(zTemp), zTemp); - if( n < 1 ){ - /* Assume the default windows temp directory */ - jx9_result_string(pCtx, "C:\\Windows\\Temp", -1/*Compute length automatically*/); - }else{ - jx9_result_string(pCtx, zTemp, (int)n); - } -} -/* unsigned int (*xProcessId)(void) */ -static unsigned int WinVfs_ProcessId(void) -{ - DWORD nID = 0; -#ifndef __MINGW32__ - nID = GetProcessId(GetCurrentProcess()); -#endif /* __MINGW32__ */ - return (unsigned int)nID; -} - -/* Export the windows vfs */ -static const jx9_vfs sWinVfs = { - "Windows_vfs", - JX9_VFS_VERSION, - WinVfs_chdir, /* int (*xChdir)(const char *) */ - 0, /* int (*xChroot)(const char *); */ - WinVfs_getcwd, /* int (*xGetcwd)(jx9_context *) */ - WinVfs_mkdir, /* int (*xMkdir)(const char *, int, int) */ - WinVfs_rmdir, /* int (*xRmdir)(const char *) */ - WinVfs_isdir, /* int (*xIsdir)(const char *) */ - WinVfs_Rename, /* int (*xRename)(const char *, const char *) */ - WinVfs_Realpath, /*int (*xRealpath)(const char *, jx9_context *)*/ - WinVfs_Sleep, /* int (*xSleep)(unsigned int) */ - WinVfs_unlink, /* int (*xUnlink)(const char *) */ - WinVfs_FileExists, /* int (*xFileExists)(const char *) */ - 0, /*int (*xChmod)(const char *, int)*/ - 0, /*int (*xChown)(const char *, const char *)*/ - 0, /*int (*xChgrp)(const char *, const char *)*/ - WinVfs_DiskFreeSpace, /* jx9_int64 (*xFreeSpace)(const char *) */ - WinVfs_DiskTotalSpace, /* jx9_int64 (*xTotalSpace)(const char *) */ - WinVfs_FileSize, /* jx9_int64 (*xFileSize)(const char *) */ - WinVfs_FileAtime, /* jx9_int64 (*xFileAtime)(const char *) */ - WinVfs_FileMtime, /* jx9_int64 (*xFileMtime)(const char *) */ - WinVfs_FileCtime, /* jx9_int64 (*xFileCtime)(const char *) */ - WinVfs_Stat, /* int (*xStat)(const char *, jx9_value *, jx9_value *) */ - WinVfs_Stat, /* int (*xlStat)(const char *, jx9_value *, jx9_value *) */ - WinVfs_isfile, /* int (*xIsfile)(const char *) */ - WinVfs_islink, /* int (*xIslink)(const char *) */ - WinVfs_isfile, /* int (*xReadable)(const char *) */ - WinVfs_iswritable, /* int (*xWritable)(const char *) */ - WinVfs_isexecutable, /* int (*xExecutable)(const char *) */ - WinVfs_Filetype, /* int (*xFiletype)(const char *, jx9_context *) */ - WinVfs_Getenv, /* int (*xGetenv)(const char *, jx9_context *) */ - WinVfs_Setenv, /* int (*xSetenv)(const char *, const char *) */ - WinVfs_Touch, /* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ - WinVfs_Mmap, /* int (*xMmap)(const char *, void **, jx9_int64 *) */ - WinVfs_Unmap, /* void (*xUnmap)(void *, jx9_int64); */ - 0, /* int (*xLink)(const char *, const char *, int) */ - 0, /* int (*xUmask)(int) */ - WinVfs_TempDir, /* void (*xTempDir)(jx9_context *) */ - WinVfs_ProcessId, /* unsigned int (*xProcessId)(void) */ - 0, /* int (*xUid)(void) */ - 0, /* int (*xGid)(void) */ - 0, /* void (*xUsername)(jx9_context *) */ - 0 /* int (*xExec)(const char *, jx9_context *) */ -}; -/* Windows file IO */ -#ifndef INVALID_SET_FILE_POINTER -# define INVALID_SET_FILE_POINTER ((DWORD)-1) -#endif -/* int (*xOpen)(const char *, int, jx9_value *, void **) */ -static int WinFile_Open(const char *zPath, int iOpenMode, jx9_value *pResource, void **ppHandle) -{ - DWORD dwType = FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS; - DWORD dwAccess = GENERIC_READ; - DWORD dwShare, dwCreate; - void *pConverted; - HANDLE pHandle; - - pConverted = jx9convertUtf8Filename(zPath); - if( pConverted == 0 ){ - return -1; - } - /* Set the desired flags according to the open mode */ - if( iOpenMode & JX9_IO_OPEN_CREATE ){ - /* Open existing file, or create if it doesn't exist */ - dwCreate = OPEN_ALWAYS; - if( iOpenMode & JX9_IO_OPEN_TRUNC ){ - /* If the specified file exists and is writable, the function overwrites the file */ - dwCreate = CREATE_ALWAYS; - } - }else if( iOpenMode & JX9_IO_OPEN_EXCL ){ - /* Creates a new file, only if it does not already exist. - * If the file exists, it fails. - */ - dwCreate = CREATE_NEW; - }else if( iOpenMode & JX9_IO_OPEN_TRUNC ){ - /* Opens a file and truncates it so that its size is zero bytes - * The file must exist. - */ - dwCreate = TRUNCATE_EXISTING; - }else{ - /* Opens a file, only if it exists. */ - dwCreate = OPEN_EXISTING; - } - if( iOpenMode & JX9_IO_OPEN_RDWR ){ - /* Read+Write access */ - dwAccess |= GENERIC_WRITE; - }else if( iOpenMode & JX9_IO_OPEN_WRONLY ){ - /* Write only access */ - dwAccess = GENERIC_WRITE; - } - if( iOpenMode & JX9_IO_OPEN_APPEND ){ - /* Append mode */ - dwAccess = FILE_APPEND_DATA; - } - if( iOpenMode & JX9_IO_OPEN_TEMP ){ - /* File is temporary */ - dwType = FILE_ATTRIBUTE_TEMPORARY; - } - dwShare = FILE_SHARE_READ | FILE_SHARE_WRITE; - pHandle = CreateFileW((LPCWSTR)pConverted, dwAccess, dwShare, 0, dwCreate, dwType, 0); - HeapFree(GetProcessHeap(), 0, pConverted); - if( pHandle == INVALID_HANDLE_VALUE){ - SXUNUSED(pResource); /* MSVC warning */ - return -1; - } - /* Make the handle accessible to the upper layer */ - *ppHandle = (void *)pHandle; - return JX9_OK; -} -/* An instance of the following structure is used to record state information - * while iterating throw directory entries. - */ -typedef struct WinDir_Info WinDir_Info; -struct WinDir_Info -{ - HANDLE pDirHandle; - void *pPath; - WIN32_FIND_DATAW sInfo; - int rc; -}; -/* int (*xOpenDir)(const char *, jx9_value *, void **) */ -static int WinDir_Open(const char *zPath, jx9_value *pResource, void **ppHandle) -{ - WinDir_Info *pDirInfo; - void *pConverted; - char *zPrep; - sxu32 n; - /* Prepare the path */ - n = SyStrlen(zPath); - zPrep = (char *)HeapAlloc(GetProcessHeap(), 0, n+sizeof("\\*")+4); - if( zPrep == 0 ){ - return -1; - } - SyMemcpy((const void *)zPath, zPrep, n); - zPrep[n] = '\\'; - zPrep[n+1] = '*'; - zPrep[n+2] = 0; - pConverted = jx9convertUtf8Filename(zPrep); - HeapFree(GetProcessHeap(), 0, zPrep); - if( pConverted == 0 ){ - return -1; - } - /* Allocate a new instance */ - pDirInfo = (WinDir_Info *)HeapAlloc(GetProcessHeap(), 0, sizeof(WinDir_Info)); - if( pDirInfo == 0 ){ - pResource = 0; /* Compiler warning */ - return -1; - } - pDirInfo->rc = SXRET_OK; - pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pConverted, &pDirInfo->sInfo); - if( pDirInfo->pDirHandle == INVALID_HANDLE_VALUE ){ - /* Cannot open directory */ - HeapFree(GetProcessHeap(), 0, pConverted); - HeapFree(GetProcessHeap(), 0, pDirInfo); - return -1; - } - /* Save the path */ - pDirInfo->pPath = pConverted; - /* Save our structure */ - *ppHandle = pDirInfo; - return JX9_OK; -} -/* void (*xCloseDir)(void *) */ -static void WinDir_Close(void *pUserData) -{ - WinDir_Info *pDirInfo = (WinDir_Info *)pUserData; - if( pDirInfo->pDirHandle != INVALID_HANDLE_VALUE ){ - FindClose(pDirInfo->pDirHandle); - } - HeapFree(GetProcessHeap(), 0, pDirInfo->pPath); - HeapFree(GetProcessHeap(), 0, pDirInfo); -} -/* void (*xClose)(void *); */ -static void WinFile_Close(void *pUserData) -{ - HANDLE pHandle = (HANDLE)pUserData; - CloseHandle(pHandle); -} -/* int (*xReadDir)(void *, jx9_context *) */ -static int WinDir_Read(void *pUserData, jx9_context *pCtx) -{ - WinDir_Info *pDirInfo = (WinDir_Info *)pUserData; - LPWIN32_FIND_DATAW pData; - char *zName; - BOOL rc; - sxu32 n; - if( pDirInfo->rc != SXRET_OK ){ - /* No more entry to process */ - return -1; - } - pData = &pDirInfo->sInfo; - for(;;){ - zName = jx9unicodeToUtf8(pData->cFileName); - if( zName == 0 ){ - /* Out of memory */ - return -1; - } - n = SyStrlen(zName); - /* Ignore '.' && '..' */ - if( n > sizeof("..")-1 || zName[0] != '.' || ( n == sizeof("..")-1 && zName[1] != '.') ){ - break; - } - HeapFree(GetProcessHeap(), 0, zName); - rc = FindNextFileW(pDirInfo->pDirHandle, &pDirInfo->sInfo); - if( !rc ){ - return -1; - } - } - /* Return the current file name */ - jx9_result_string(pCtx, zName, -1); - HeapFree(GetProcessHeap(), 0, zName); - /* Point to the next entry */ - rc = FindNextFileW(pDirInfo->pDirHandle, &pDirInfo->sInfo); - if( !rc ){ - pDirInfo->rc = SXERR_EOF; - } - return JX9_OK; -} -/* void (*xRewindDir)(void *) */ -static void WinDir_RewindDir(void *pUserData) -{ - WinDir_Info *pDirInfo = (WinDir_Info *)pUserData; - FindClose(pDirInfo->pDirHandle); - pDirInfo->pDirHandle = FindFirstFileW((LPCWSTR)pDirInfo->pPath, &pDirInfo->sInfo); - if( pDirInfo->pDirHandle == INVALID_HANDLE_VALUE ){ - pDirInfo->rc = SXERR_EOF; - }else{ - pDirInfo->rc = SXRET_OK; - } -} -/* jx9_int64 (*xRead)(void *, void *, jx9_int64); */ -static jx9_int64 WinFile_Read(void *pOS, void *pBuffer, jx9_int64 nDatatoRead) -{ - HANDLE pHandle = (HANDLE)pOS; - DWORD nRd; - BOOL rc; - rc = ReadFile(pHandle, pBuffer, (DWORD)nDatatoRead, &nRd, 0); - if( !rc ){ - /* EOF or IO error */ - return -1; - } - return (jx9_int64)nRd; -} -/* jx9_int64 (*xWrite)(void *, const void *, jx9_int64); */ -static jx9_int64 WinFile_Write(void *pOS, const void *pBuffer, jx9_int64 nWrite) -{ - const char *zData = (const char *)pBuffer; - HANDLE pHandle = (HANDLE)pOS; - jx9_int64 nCount; - DWORD nWr; - BOOL rc; - nWr = 0; - nCount = 0; - for(;;){ - if( nWrite < 1 ){ - break; - } - rc = WriteFile(pHandle, zData, (DWORD)nWrite, &nWr, 0); - if( !rc ){ - /* IO error */ - break; - } - nWrite -= nWr; - nCount += nWr; - zData += nWr; - } - if( nWrite > 0 ){ - return -1; - } - return nCount; -} -/* int (*xSeek)(void *, jx9_int64, int) */ -static int WinFile_Seek(void *pUserData, jx9_int64 iOfft, int whence) -{ - HANDLE pHandle = (HANDLE)pUserData; - DWORD dwMove, dwNew; - LONG nHighOfft; - switch(whence){ - case 1:/*SEEK_CUR*/ - dwMove = FILE_CURRENT; - break; - case 2: /* SEEK_END */ - dwMove = FILE_END; - break; - case 0: /* SEEK_SET */ - default: - dwMove = FILE_BEGIN; - break; - } - nHighOfft = (LONG)(iOfft >> 32); - dwNew = SetFilePointer(pHandle, (LONG)iOfft, &nHighOfft, dwMove); - if( dwNew == INVALID_SET_FILE_POINTER ){ - return -1; - } - return JX9_OK; -} -/* int (*xLock)(void *, int) */ -static int WinFile_Lock(void *pUserData, int lock_type) -{ - HANDLE pHandle = (HANDLE)pUserData; - static DWORD dwLo = 0, dwHi = 0; /* xx: MT-SAFE */ - OVERLAPPED sDummy; - BOOL rc; - SyZero(&sDummy, sizeof(sDummy)); - /* Get the file size */ - if( lock_type < 1 ){ - /* Unlock the file */ - rc = UnlockFileEx(pHandle, 0, dwLo, dwHi, &sDummy); - }else{ - DWORD dwFlags = LOCKFILE_FAIL_IMMEDIATELY; /* Shared non-blocking lock by default*/ - /* Lock the file */ - if( lock_type == 1 /* LOCK_EXCL */ ){ - dwFlags |= LOCKFILE_EXCLUSIVE_LOCK; - } - dwLo = GetFileSize(pHandle, &dwHi); - rc = LockFileEx(pHandle, dwFlags, 0, dwLo, dwHi, &sDummy); - } - return rc ? JX9_OK : -1 /* Lock error */; -} -/* jx9_int64 (*xTell)(void *) */ -static jx9_int64 WinFile_Tell(void *pUserData) -{ - HANDLE pHandle = (HANDLE)pUserData; - DWORD dwNew; - dwNew = SetFilePointer(pHandle, 0, 0, FILE_CURRENT/* SEEK_CUR */); - if( dwNew == INVALID_SET_FILE_POINTER ){ - return -1; - } - return (jx9_int64)dwNew; -} -/* int (*xTrunc)(void *, jx9_int64) */ -static int WinFile_Trunc(void *pUserData, jx9_int64 nOfft) -{ - HANDLE pHandle = (HANDLE)pUserData; - LONG HighOfft; - DWORD dwNew; - BOOL rc; - HighOfft = (LONG)(nOfft >> 32); - dwNew = SetFilePointer(pHandle, (LONG)nOfft, &HighOfft, FILE_BEGIN); - if( dwNew == INVALID_SET_FILE_POINTER ){ - return -1; - } - rc = SetEndOfFile(pHandle); - return rc ? JX9_OK : -1; -} -/* int (*xSync)(void *); */ -static int WinFile_Sync(void *pUserData) -{ - HANDLE pHandle = (HANDLE)pUserData; - BOOL rc; - rc = FlushFileBuffers(pHandle); - return rc ? JX9_OK : - 1; -} -/* int (*xStat)(void *, jx9_value *, jx9_value *) */ -static int WinFile_Stat(void *pUserData, jx9_value *pArray, jx9_value *pWorker) -{ - BY_HANDLE_FILE_INFORMATION sInfo; - HANDLE pHandle = (HANDLE)pUserData; - BOOL rc; - rc = GetFileInformationByHandle(pHandle, &sInfo); - if( !rc ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)sInfo.dwVolumeSerialNumber); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileIndexHigh << 32) | sInfo.nFileIndexLow)); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)sInfo.nNumberOfLinks); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)(((jx9_int64)sInfo.nFileSizeHigh << 32) | sInfo.nFileSizeLow)); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastAccessTime)); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftLastWriteTime)); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, convertWindowsTimeToUnixTime(&sInfo.ftCreationTime)); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, 0); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* Export the file:// stream */ -static const jx9_io_stream sWinFileStream = { - "file", /* Stream name */ - JX9_IO_STREAM_VERSION, - WinFile_Open, /* xOpen */ - WinDir_Open, /* xOpenDir */ - WinFile_Close, /* xClose */ - WinDir_Close, /* xCloseDir */ - WinFile_Read, /* xRead */ - WinDir_Read, /* xReadDir */ - WinFile_Write, /* xWrite */ - WinFile_Seek, /* xSeek */ - WinFile_Lock, /* xLock */ - WinDir_RewindDir, /* xRewindDir */ - WinFile_Tell, /* xTell */ - WinFile_Trunc, /* xTrunc */ - WinFile_Sync, /* xSeek */ - WinFile_Stat /* xStat */ -}; -#elif defined(__UNIXES__) -/* - * UNIX VFS implementation for the JX9 engine. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -/* int (*xchdir)(const char *) */ -static int UnixVfs_chdir(const char *zPath) -{ - int rc; - rc = chdir(zPath); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xGetcwd)(jx9_context *) */ -static int UnixVfs_getcwd(jx9_context *pCtx) -{ - char zBuf[4096]; - char *zDir; - /* Get the current directory */ - zDir = getcwd(zBuf, sizeof(zBuf)); - if( zDir == 0 ){ - return -1; - } - jx9_result_string(pCtx, zDir, -1/*Compute length automatically*/); - return JX9_OK; -} -/* int (*xMkdir)(const char *, int, int) */ -static int UnixVfs_mkdir(const char *zPath, int mode, int recursive) -{ - int rc; - rc = mkdir(zPath, mode); - recursive = 0; /* cc warning */ - return rc == 0 ? JX9_OK : -1; -} -/* int (*xRmdir)(const char *) */ -static int UnixVfs_rmdir(const char *zPath) -{ - int rc; - rc = rmdir(zPath); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xIsdir)(const char *) */ -static int UnixVfs_isdir(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - rc = S_ISDIR(st.st_mode); - return rc ? JX9_OK : -1 ; -} -/* int (*xRename)(const char *, const char *) */ -static int UnixVfs_Rename(const char *zOld, const char *zNew) -{ - int rc; - rc = rename(zOld, zNew); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xRealpath)(const char *, jx9_context *) */ -static int UnixVfs_Realpath(const char *zPath, jx9_context *pCtx) -{ -#ifndef JX9_UNIX_OLD_LIBC - char *zReal; - zReal = realpath(zPath, 0); - if( zReal == 0 ){ - return -1; - } - jx9_result_string(pCtx, zReal, -1/*Compute length automatically*/); - /* Release the allocated buffer */ - free(zReal); - return JX9_OK; -#else - zPath = 0; /* cc warning */ - pCtx = 0; - return -1; -#endif -} -/* int (*xSleep)(unsigned int) */ -static int UnixVfs_Sleep(unsigned int uSec) -{ - usleep(uSec); - return JX9_OK; -} -/* int (*xUnlink)(const char *) */ -static int UnixVfs_unlink(const char *zPath) -{ - int rc; - rc = unlink(zPath); - return rc == 0 ? JX9_OK : -1 ; -} -/* int (*xFileExists)(const char *) */ -static int UnixVfs_FileExists(const char *zPath) -{ - int rc; - rc = access(zPath, F_OK); - return rc == 0 ? JX9_OK : -1; -} -/* jx9_int64 (*xFileSize)(const char *) */ -static jx9_int64 UnixVfs_FileSize(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_size; -} -/* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ -static int UnixVfs_Touch(const char *zPath, jx9_int64 touch_time, jx9_int64 access_time) -{ - struct utimbuf ut; - int rc; - ut.actime = (time_t)access_time; - ut.modtime = (time_t)touch_time; - rc = utime(zPath, &ut); - if( rc != 0 ){ - return -1; - } - return JX9_OK; -} -/* jx9_int64 (*xFileAtime)(const char *) */ -static jx9_int64 UnixVfs_FileAtime(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_atime; -} -/* jx9_int64 (*xFileMtime)(const char *) */ -static jx9_int64 UnixVfs_FileMtime(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_mtime; -} -/* jx9_int64 (*xFileCtime)(const char *) */ -static jx9_int64 UnixVfs_FileCtime(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - return (jx9_int64)st.st_ctime; -} -/* int (*xStat)(const char *, jx9_value *, jx9_value *) */ -static int UnixVfs_Stat(const char *zPath, jx9_value *pArray, jx9_value *pWorker) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)st.st_dev); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ino); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, (int)st.st_mode); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)st.st_nlink); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, (int)st.st_uid); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_value_int(pWorker, (int)st.st_gid); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_value_int(pWorker, (int)st.st_rdev); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)st.st_size); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_atime); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_mtime); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ctime); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, (int)st.st_blksize); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_value_int(pWorker, (int)st.st_blocks); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* int (*xlStat)(const char *, jx9_value *, jx9_value *) */ -static int UnixVfs_lStat(const char *zPath, jx9_value *pArray, jx9_value *pWorker) -{ - struct stat st; - int rc; - rc = lstat(zPath, &st); - if( rc != 0 ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)st.st_dev); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ino); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, (int)st.st_mode); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)st.st_nlink); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, (int)st.st_uid); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_value_int(pWorker, (int)st.st_gid); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_value_int(pWorker, (int)st.st_rdev); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)st.st_size); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_atime); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_mtime); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ctime); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, (int)st.st_blksize); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_value_int(pWorker, (int)st.st_blocks); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* int (*xChmod)(const char *, int) */ -static int UnixVfs_Chmod(const char *zPath, int mode) -{ - int rc; - rc = chmod(zPath, (mode_t)mode); - return rc == 0 ? JX9_OK : - 1; -} -/* int (*xChown)(const char *, const char *) */ -static int UnixVfs_Chown(const char *zPath, const char *zUser) -{ -#ifndef JX9_UNIX_STATIC_BUILD - struct passwd *pwd; - uid_t uid; - int rc; - pwd = getpwnam(zUser); /* Try getting UID for username */ - if (pwd == 0) { - return -1; - } - uid = pwd->pw_uid; - rc = chown(zPath, uid, -1); - return rc == 0 ? JX9_OK : -1; -#else - SXUNUSED(zPath); - SXUNUSED(zUser); - return -1; -#endif /* JX9_UNIX_STATIC_BUILD */ -} -/* int (*xChgrp)(const char *, const char *) */ -static int UnixVfs_Chgrp(const char *zPath, const char *zGroup) -{ -#ifndef JX9_UNIX_STATIC_BUILD - struct group *group; - gid_t gid; - int rc; - group = getgrnam(zGroup); - if (group == 0) { - return -1; - } - gid = group->gr_gid; - rc = chown(zPath, -1, gid); - return rc == 0 ? JX9_OK : -1; -#else - SXUNUSED(zPath); - SXUNUSED(zGroup); - return -1; -#endif /* JX9_UNIX_STATIC_BUILD */ -} -/* int (*xIsfile)(const char *) */ -static int UnixVfs_isfile(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - rc = S_ISREG(st.st_mode); - return rc ? JX9_OK : -1 ; -} -/* int (*xIslink)(const char *) */ -static int UnixVfs_islink(const char *zPath) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - return -1; - } - rc = S_ISLNK(st.st_mode); - return rc ? JX9_OK : -1 ; -} -/* int (*xReadable)(const char *) */ -static int UnixVfs_isreadable(const char *zPath) -{ - int rc; - rc = access(zPath, R_OK); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xWritable)(const char *) */ -static int UnixVfs_iswritable(const char *zPath) -{ - int rc; - rc = access(zPath, W_OK); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xExecutable)(const char *) */ -static int UnixVfs_isexecutable(const char *zPath) -{ - int rc; - rc = access(zPath, X_OK); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xFiletype)(const char *, jx9_context *) */ -static int UnixVfs_Filetype(const char *zPath, jx9_context *pCtx) -{ - struct stat st; - int rc; - rc = stat(zPath, &st); - if( rc != 0 ){ - /* Expand 'unknown' */ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - return -1; - } - if(S_ISREG(st.st_mode) ){ - jx9_result_string(pCtx, "file", sizeof("file")-1); - }else if(S_ISDIR(st.st_mode)){ - jx9_result_string(pCtx, "dir", sizeof("dir")-1); - }else if(S_ISLNK(st.st_mode)){ - jx9_result_string(pCtx, "link", sizeof("link")-1); - }else if(S_ISBLK(st.st_mode)){ - jx9_result_string(pCtx, "block", sizeof("block")-1); - }else if(S_ISSOCK(st.st_mode)){ - jx9_result_string(pCtx, "socket", sizeof("socket")-1); - }else if(S_ISFIFO(st.st_mode)){ - jx9_result_string(pCtx, "fifo", sizeof("fifo")-1); - }else{ - jx9_result_string(pCtx, "unknown", sizeof("unknown")-1); - } - return JX9_OK; -} -/* int (*xGetenv)(const char *, jx9_context *) */ -static int UnixVfs_Getenv(const char *zVar, jx9_context *pCtx) -{ - char *zEnv; - zEnv = getenv(zVar); - if( zEnv == 0 ){ - return -1; - } - jx9_result_string(pCtx, zEnv, -1/*Compute length automatically*/); - return JX9_OK; -} -/* int (*xSetenv)(const char *, const char *) */ -static int UnixVfs_Setenv(const char *zName, const char *zValue) -{ - int rc; - rc = setenv(zName, zValue, 1); - return rc == 0 ? JX9_OK : -1; -} -/* int (*xMmap)(const char *, void **, jx9_int64 *) */ -static int UnixVfs_Mmap(const char *zPath, void **ppMap, jx9_int64 *pSize) -{ - struct stat st; - void *pMap; - int fd; - int rc; - /* Open the file in a read-only mode */ - fd = open(zPath, O_RDONLY); - if( fd < 0 ){ - return -1; - } - /* stat the handle */ - fstat(fd, &st); - /* Obtain a memory view of the whole file */ - pMap = mmap(0, st.st_size, PROT_READ, MAP_PRIVATE|MAP_FILE, fd, 0); - rc = JX9_OK; - if( pMap == MAP_FAILED ){ - rc = -1; - }else{ - /* Point to the memory view */ - *ppMap = pMap; - *pSize = (jx9_int64)st.st_size; - } - close(fd); - return rc; -} -/* void (*xUnmap)(void *, jx9_int64) */ -static void UnixVfs_Unmap(void *pView, jx9_int64 nSize) -{ - munmap(pView, (size_t)nSize); -} -/* void (*xTempDir)(jx9_context *) */ -static void UnixVfs_TempDir(jx9_context *pCtx) -{ - static const char *azDirs[] = { - "/var/tmp", - "/usr/tmp", - "/usr/local/tmp" - }; - unsigned int i; - struct stat buf; - const char *zDir; - zDir = getenv("TMPDIR"); - if( zDir && zDir[0] != 0 && !access(zDir, 07) ){ - jx9_result_string(pCtx, zDir, -1); - return; - } - for(i=0; ipw_name, -1); -#else - jx9_result_string(pCtx, "Unknown", -1); -#endif /* JX9_UNIX_STATIC_BUILD */ - return; -} -/* int (*xLink)(const char *, const char *, int) */ -static int UnixVfs_link(const char *zSrc, const char *zTarget, int is_sym) -{ - int rc; - if( is_sym ){ - /* Symbolic link */ - rc = symlink(zSrc, zTarget); - }else{ - /* Hard link */ - rc = link(zSrc, zTarget); - } - return rc == 0 ? JX9_OK : -1; -} -/* int (*xChroot)(const char *) */ -static int UnixVfs_chroot(const char *zRootDir) -{ - int rc; - rc = chroot(zRootDir); - return rc == 0 ? JX9_OK : -1; -} -/* Export the UNIX vfs */ -static const jx9_vfs sUnixVfs = { - "Unix_vfs", - JX9_VFS_VERSION, - UnixVfs_chdir, /* int (*xChdir)(const char *) */ - UnixVfs_chroot, /* int (*xChroot)(const char *); */ - UnixVfs_getcwd, /* int (*xGetcwd)(jx9_context *) */ - UnixVfs_mkdir, /* int (*xMkdir)(const char *, int, int) */ - UnixVfs_rmdir, /* int (*xRmdir)(const char *) */ - UnixVfs_isdir, /* int (*xIsdir)(const char *) */ - UnixVfs_Rename, /* int (*xRename)(const char *, const char *) */ - UnixVfs_Realpath, /*int (*xRealpath)(const char *, jx9_context *)*/ - UnixVfs_Sleep, /* int (*xSleep)(unsigned int) */ - UnixVfs_unlink, /* int (*xUnlink)(const char *) */ - UnixVfs_FileExists, /* int (*xFileExists)(const char *) */ - UnixVfs_Chmod, /*int (*xChmod)(const char *, int)*/ - UnixVfs_Chown, /*int (*xChown)(const char *, const char *)*/ - UnixVfs_Chgrp, /*int (*xChgrp)(const char *, const char *)*/ - 0, /* jx9_int64 (*xFreeSpace)(const char *) */ - 0, /* jx9_int64 (*xTotalSpace)(const char *) */ - UnixVfs_FileSize, /* jx9_int64 (*xFileSize)(const char *) */ - UnixVfs_FileAtime, /* jx9_int64 (*xFileAtime)(const char *) */ - UnixVfs_FileMtime, /* jx9_int64 (*xFileMtime)(const char *) */ - UnixVfs_FileCtime, /* jx9_int64 (*xFileCtime)(const char *) */ - UnixVfs_Stat, /* int (*xStat)(const char *, jx9_value *, jx9_value *) */ - UnixVfs_lStat, /* int (*xlStat)(const char *, jx9_value *, jx9_value *) */ - UnixVfs_isfile, /* int (*xIsfile)(const char *) */ - UnixVfs_islink, /* int (*xIslink)(const char *) */ - UnixVfs_isreadable, /* int (*xReadable)(const char *) */ - UnixVfs_iswritable, /* int (*xWritable)(const char *) */ - UnixVfs_isexecutable, /* int (*xExecutable)(const char *) */ - UnixVfs_Filetype, /* int (*xFiletype)(const char *, jx9_context *) */ - UnixVfs_Getenv, /* int (*xGetenv)(const char *, jx9_context *) */ - UnixVfs_Setenv, /* int (*xSetenv)(const char *, const char *) */ - UnixVfs_Touch, /* int (*xTouch)(const char *, jx9_int64, jx9_int64) */ - UnixVfs_Mmap, /* int (*xMmap)(const char *, void **, jx9_int64 *) */ - UnixVfs_Unmap, /* void (*xUnmap)(void *, jx9_int64); */ - UnixVfs_link, /* int (*xLink)(const char *, const char *, int) */ - UnixVfs_Umask, /* int (*xUmask)(int) */ - UnixVfs_TempDir, /* void (*xTempDir)(jx9_context *) */ - UnixVfs_ProcessId, /* unsigned int (*xProcessId)(void) */ - UnixVfs_uid, /* int (*xUid)(void) */ - UnixVfs_gid, /* int (*xGid)(void) */ - UnixVfs_Username, /* void (*xUsername)(jx9_context *) */ - 0 /* int (*xExec)(const char *, jx9_context *) */ -}; -/* UNIX File IO */ -#define JX9_UNIX_OPEN_MODE 0640 /* Default open mode */ -/* int (*xOpen)(const char *, int, jx9_value *, void **) */ -static int UnixFile_Open(const char *zPath, int iOpenMode, jx9_value *pResource, void **ppHandle) -{ - int iOpen = O_RDONLY; - int fd; - /* Set the desired flags according to the open mode */ - if( iOpenMode & JX9_IO_OPEN_CREATE ){ - /* Open existing file, or create if it doesn't exist */ - iOpen = O_CREAT; - if( iOpenMode & JX9_IO_OPEN_TRUNC ){ - /* If the specified file exists and is writable, the function overwrites the file */ - iOpen |= O_TRUNC; - SXUNUSED(pResource); /* cc warning */ - } - }else if( iOpenMode & JX9_IO_OPEN_EXCL ){ - /* Creates a new file, only if it does not already exist. - * If the file exists, it fails. - */ - iOpen = O_CREAT|O_EXCL; - }else if( iOpenMode & JX9_IO_OPEN_TRUNC ){ - /* Opens a file and truncates it so that its size is zero bytes - * The file must exist. - */ - iOpen = O_RDWR|O_TRUNC; - } - if( iOpenMode & JX9_IO_OPEN_RDWR ){ - /* Read+Write access */ - iOpen &= ~O_RDONLY; - iOpen |= O_RDWR; - }else if( iOpenMode & JX9_IO_OPEN_WRONLY ){ - /* Write only access */ - iOpen &= ~O_RDONLY; - iOpen |= O_WRONLY; - } - if( iOpenMode & JX9_IO_OPEN_APPEND ){ - /* Append mode */ - iOpen |= O_APPEND; - } -#ifdef O_TEMP - if( iOpenMode & JX9_IO_OPEN_TEMP ){ - /* File is temporary */ - iOpen |= O_TEMP; - } -#endif - /* Open the file now */ - fd = open(zPath, iOpen, JX9_UNIX_OPEN_MODE); - if( fd < 0 ){ - /* IO error */ - return -1; - } - /* Save the handle */ - *ppHandle = SX_INT_TO_PTR(fd); - return JX9_OK; -} -/* int (*xOpenDir)(const char *, jx9_value *, void **) */ -static int UnixDir_Open(const char *zPath, jx9_value *pResource, void **ppHandle) -{ - DIR *pDir; - /* Open the target directory */ - pDir = opendir(zPath); - if( pDir == 0 ){ - pResource = 0; /* Compiler warning */ - return -1; - } - /* Save our structure */ - *ppHandle = pDir; - return JX9_OK; -} -/* void (*xCloseDir)(void *) */ -static void UnixDir_Close(void *pUserData) -{ - closedir((DIR *)pUserData); -} -/* void (*xClose)(void *); */ -static void UnixFile_Close(void *pUserData) -{ - close(SX_PTR_TO_INT(pUserData)); -} -/* int (*xReadDir)(void *, jx9_context *) */ -static int UnixDir_Read(void *pUserData, jx9_context *pCtx) -{ - DIR *pDir = (DIR *)pUserData; - struct dirent *pEntry; - char *zName = 0; /* cc warning */ - sxu32 n = 0; - for(;;){ - pEntry = readdir(pDir); - if( pEntry == 0 ){ - /* No more entries to process */ - return -1; - } - zName = pEntry->d_name; - n = SyStrlen(zName); - /* Ignore '.' && '..' */ - if( n > sizeof("..")-1 || zName[0] != '.' || ( n == sizeof("..")-1 && zName[1] != '.') ){ - break; - } - /* Next entry */ - } - /* Return the current file name */ - jx9_result_string(pCtx, zName, (int)n); - return JX9_OK; -} -/* void (*xRewindDir)(void *) */ -static void UnixDir_Rewind(void *pUserData) -{ - rewinddir((DIR *)pUserData); -} -/* jx9_int64 (*xRead)(void *, void *, jx9_int64); */ -static jx9_int64 UnixFile_Read(void *pUserData, void *pBuffer, jx9_int64 nDatatoRead) -{ - ssize_t nRd; - nRd = read(SX_PTR_TO_INT(pUserData), pBuffer, (size_t)nDatatoRead); - if( nRd < 1 ){ - /* EOF or IO error */ - return -1; - } - return (jx9_int64)nRd; -} -/* jx9_int64 (*xWrite)(void *, const void *, jx9_int64); */ -static jx9_int64 UnixFile_Write(void *pUserData, const void *pBuffer, jx9_int64 nWrite) -{ - const char *zData = (const char *)pBuffer; - int fd = SX_PTR_TO_INT(pUserData); - jx9_int64 nCount; - ssize_t nWr; - nCount = 0; - for(;;){ - if( nWrite < 1 ){ - break; - } - nWr = write(fd, zData, (size_t)nWrite); - if( nWr < 1 ){ - /* IO error */ - break; - } - nWrite -= nWr; - nCount += nWr; - zData += nWr; - } - if( nWrite > 0 ){ - return -1; - } - return nCount; -} -/* int (*xSeek)(void *, jx9_int64, int) */ -static int UnixFile_Seek(void *pUserData, jx9_int64 iOfft, int whence) -{ - off_t iNew; - switch(whence){ - case 1:/*SEEK_CUR*/ - whence = SEEK_CUR; - break; - case 2: /* SEEK_END */ - whence = SEEK_END; - break; - case 0: /* SEEK_SET */ - default: - whence = SEEK_SET; - break; - } - iNew = lseek(SX_PTR_TO_INT(pUserData), (off_t)iOfft, whence); - if( iNew < 0 ){ - return -1; - } - return JX9_OK; -} -/* int (*xLock)(void *, int) */ -static int UnixFile_Lock(void *pUserData, int lock_type) -{ - int fd = SX_PTR_TO_INT(pUserData); - int rc = JX9_OK; /* cc warning */ - if( lock_type < 0 ){ - /* Unlock the file */ - rc = flock(fd, LOCK_UN); - }else{ - if( lock_type == 1 ){ - /* Exculsive lock */ - rc = flock(fd, LOCK_EX); - }else{ - /* Shared lock */ - rc = flock(fd, LOCK_SH); - } - } - return !rc ? JX9_OK : -1; -} -/* jx9_int64 (*xTell)(void *) */ -static jx9_int64 UnixFile_Tell(void *pUserData) -{ - off_t iNew; - iNew = lseek(SX_PTR_TO_INT(pUserData), 0, SEEK_CUR); - return (jx9_int64)iNew; -} -/* int (*xTrunc)(void *, jx9_int64) */ -static int UnixFile_Trunc(void *pUserData, jx9_int64 nOfft) -{ - int rc; - rc = ftruncate(SX_PTR_TO_INT(pUserData), (off_t)nOfft); - if( rc != 0 ){ - return -1; - } - return JX9_OK; -} -/* int (*xSync)(void *); */ -static int UnixFile_Sync(void *pUserData) -{ - int rc; - rc = fsync(SX_PTR_TO_INT(pUserData)); - return rc == 0 ? JX9_OK : - 1; -} -/* int (*xStat)(void *, jx9_value *, jx9_value *) */ -static int UnixFile_Stat(void *pUserData, jx9_value *pArray, jx9_value *pWorker) -{ - struct stat st; - int rc; - rc = fstat(SX_PTR_TO_INT(pUserData), &st); - if( rc != 0 ){ - return -1; - } - /* dev */ - jx9_value_int64(pWorker, (jx9_int64)st.st_dev); - jx9_array_add_strkey_elem(pArray, "dev", pWorker); /* Will make it's own copy */ - /* ino */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ino); - jx9_array_add_strkey_elem(pArray, "ino", pWorker); /* Will make it's own copy */ - /* mode */ - jx9_value_int(pWorker, (int)st.st_mode); - jx9_array_add_strkey_elem(pArray, "mode", pWorker); - /* nlink */ - jx9_value_int(pWorker, (int)st.st_nlink); - jx9_array_add_strkey_elem(pArray, "nlink", pWorker); /* Will make it's own copy */ - /* uid, gid, rdev */ - jx9_value_int(pWorker, (int)st.st_uid); - jx9_array_add_strkey_elem(pArray, "uid", pWorker); - jx9_value_int(pWorker, (int)st.st_gid); - jx9_array_add_strkey_elem(pArray, "gid", pWorker); - jx9_value_int(pWorker, (int)st.st_rdev); - jx9_array_add_strkey_elem(pArray, "rdev", pWorker); - /* size */ - jx9_value_int64(pWorker, (jx9_int64)st.st_size); - jx9_array_add_strkey_elem(pArray, "size", pWorker); /* Will make it's own copy */ - /* atime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_atime); - jx9_array_add_strkey_elem(pArray, "atime", pWorker); /* Will make it's own copy */ - /* mtime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_mtime); - jx9_array_add_strkey_elem(pArray, "mtime", pWorker); /* Will make it's own copy */ - /* ctime */ - jx9_value_int64(pWorker, (jx9_int64)st.st_ctime); - jx9_array_add_strkey_elem(pArray, "ctime", pWorker); /* Will make it's own copy */ - /* blksize, blocks */ - jx9_value_int(pWorker, (int)st.st_blksize); - jx9_array_add_strkey_elem(pArray, "blksize", pWorker); - jx9_value_int(pWorker, (int)st.st_blocks); - jx9_array_add_strkey_elem(pArray, "blocks", pWorker); - return JX9_OK; -} -/* Export the file:// stream */ -static const jx9_io_stream sUnixFileStream = { - "file", /* Stream name */ - JX9_IO_STREAM_VERSION, - UnixFile_Open, /* xOpen */ - UnixDir_Open, /* xOpenDir */ - UnixFile_Close, /* xClose */ - UnixDir_Close, /* xCloseDir */ - UnixFile_Read, /* xRead */ - UnixDir_Read, /* xReadDir */ - UnixFile_Write, /* xWrite */ - UnixFile_Seek, /* xSeek */ - UnixFile_Lock, /* xLock */ - UnixDir_Rewind, /* xRewindDir */ - UnixFile_Tell, /* xTell */ - UnixFile_Trunc, /* xTrunc */ - UnixFile_Sync, /* xSeek */ - UnixFile_Stat /* xStat */ -}; -#endif /* __WINNT__/__UNIXES__ */ -#endif /* JX9_DISABLE_DISK_IO */ -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* - * Export the builtin vfs. - * Return a pointer to the builtin vfs if available. - * Otherwise return the null_vfs [i.e: a no-op vfs] instead. - * Note: - * The built-in vfs is always available for Windows/UNIX systems. - * Note: - * If the engine is compiled with the JX9_DISABLE_DISK_IO/JX9_DISABLE_BUILTIN_FUNC - * directives defined then this function return the null_vfs instead. - */ -JX9_PRIVATE const jx9_vfs * jx9ExportBuiltinVfs(void) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifdef JX9_DISABLE_DISK_IO - return &null_vfs; -#else -#ifdef __WINNT__ - return &sWinVfs; -#elif defined(__UNIXES__) - return &sUnixVfs; -#else - return &null_vfs; -#endif /* __WINNT__/__UNIXES__ */ -#endif /*JX9_DISABLE_DISK_IO*/ -#else - return &null_vfs; -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_DISK_IO -/* - * The following defines are mostly used by the UNIX built and have - * no particular meaning on windows. - */ -#ifndef STDIN_FILENO -#define STDIN_FILENO 0 -#endif -#ifndef STDOUT_FILENO -#define STDOUT_FILENO 1 -#endif -#ifndef STDERR_FILENO -#define STDERR_FILENO 2 -#endif -/* - * jx9:// Accessing various I/O streams - * According to the JX9 langage reference manual - * JX9 provides a number of miscellaneous I/O streams that allow access to JX9's own input - * and output streams, the standard input, output and error file descriptors. - * jx9://stdin, jx9://stdout and jx9://stderr: - * Allow direct access to the corresponding input or output stream of the JX9 process. - * The stream references a duplicate file descriptor, so if you open jx9://stdin and later - * close it, you close only your copy of the descriptor-the actual stream referenced by STDIN is unaffected. - * jx9://stdin is read-only, whereas jx9://stdout and jx9://stderr are write-only. - * jx9://output - * jx9://output is a write-only stream that allows you to write to the output buffer - * mechanism in the same way as print and print. - */ -typedef struct jx9_stream_data jx9_stream_data; -/* Supported IO streams */ -#define JX9_IO_STREAM_STDIN 1 /* jx9://stdin */ -#define JX9_IO_STREAM_STDOUT 2 /* jx9://stdout */ -#define JX9_IO_STREAM_STDERR 3 /* jx9://stderr */ -#define JX9_IO_STREAM_OUTPUT 4 /* jx9://output */ - /* The following structure is the private data associated with the jx9:// stream */ -struct jx9_stream_data -{ - jx9_vm *pVm; /* VM that own this instance */ - int iType; /* Stream type */ - union{ - void *pHandle; /* Stream handle */ - jx9_output_consumer sConsumer; /* VM output consumer */ - }x; -}; -/* - * Allocate a new instance of the jx9_stream_data structure. - */ -static jx9_stream_data * JX9StreamDataInit(jx9_vm *pVm, int iType) -{ - jx9_stream_data *pData; - if( pVm == 0 ){ - return 0; - } - /* Allocate a new instance */ - pData = (jx9_stream_data *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(jx9_stream_data)); - if( pData == 0 ){ - return 0; - } - /* Zero the structure */ - SyZero(pData, sizeof(jx9_stream_data)); - /* Initialize fields */ - pData->iType = iType; - if( iType == JX9_IO_STREAM_OUTPUT ){ - /* Point to the default VM consumer routine. */ - pData->x.sConsumer = pVm->sVmConsumer; - }else{ -#ifdef __WINNT__ - DWORD nChannel; - switch(iType){ - case JX9_IO_STREAM_STDOUT: nChannel = STD_OUTPUT_HANDLE; break; - case JX9_IO_STREAM_STDERR: nChannel = STD_ERROR_HANDLE; break; - default: - nChannel = STD_INPUT_HANDLE; - break; - } - pData->x.pHandle = GetStdHandle(nChannel); -#else - /* Assume an UNIX system */ - int ifd = STDIN_FILENO; - switch(iType){ - case JX9_IO_STREAM_STDOUT: ifd = STDOUT_FILENO; break; - case JX9_IO_STREAM_STDERR: ifd = STDERR_FILENO; break; - default: - break; - } - pData->x.pHandle = SX_INT_TO_PTR(ifd); -#endif - } - pData->pVm = pVm; - return pData; -} -/* - * Implementation of the jx9:// IO streams routines - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* int (*xOpen)(const char *, int, jx9_value *, void **) */ -static int JX9StreamData_Open(const char *zName, int iMode, jx9_value *pResource, void ** ppHandle) -{ - jx9_stream_data *pData; - SyString sStream; - SyStringInitFromBuf(&sStream, zName, SyStrlen(zName)); - /* Trim leading and trailing white spaces */ - SyStringFullTrim(&sStream); - /* Stream to open */ - if( SyStrnicmp(sStream.zString, "stdin", sizeof("stdin")-1) == 0 ){ - iMode = JX9_IO_STREAM_STDIN; - }else if( SyStrnicmp(sStream.zString, "output", sizeof("output")-1) == 0 ){ - iMode = JX9_IO_STREAM_OUTPUT; - }else if( SyStrnicmp(sStream.zString, "stdout", sizeof("stdout")-1) == 0 ){ - iMode = JX9_IO_STREAM_STDOUT; - }else if( SyStrnicmp(sStream.zString, "stderr", sizeof("stderr")-1) == 0 ){ - iMode = JX9_IO_STREAM_STDERR; - }else{ - /* unknown stream name */ - return -1; - } - /* Create our handle */ - pData = JX9StreamDataInit(pResource?pResource->pVm:0, iMode); - if( pData == 0 ){ - return -1; - } - /* Make the handle public */ - *ppHandle = (void *)pData; - return JX9_OK; -} -/* jx9_int64 (*xRead)(void *, void *, jx9_int64) */ -static jx9_int64 JX9StreamData_Read(void *pHandle, void *pBuffer, jx9_int64 nDatatoRead) -{ - jx9_stream_data *pData = (jx9_stream_data *)pHandle; - if( pData == 0 ){ - return -1; - } - if( pData->iType != JX9_IO_STREAM_STDIN ){ - /* Forbidden */ - return -1; - } -#ifdef __WINNT__ - { - DWORD nRd; - BOOL rc; - rc = ReadFile(pData->x.pHandle, pBuffer, (DWORD)nDatatoRead, &nRd, 0); - if( !rc ){ - /* IO error */ - return -1; - } - return (jx9_int64)nRd; - } -#elif defined(__UNIXES__) - { - ssize_t nRd; - int fd; - fd = SX_PTR_TO_INT(pData->x.pHandle); - nRd = read(fd, pBuffer, (size_t)nDatatoRead); - if( nRd < 1 ){ - return -1; - } - return (jx9_int64)nRd; - } -#else - return -1; -#endif -} -/* jx9_int64 (*xWrite)(void *, const void *, jx9_int64) */ -static jx9_int64 JX9StreamData_Write(void *pHandle, const void *pBuf, jx9_int64 nWrite) -{ - jx9_stream_data *pData = (jx9_stream_data *)pHandle; - if( pData == 0 ){ - return -1; - } - if( pData->iType == JX9_IO_STREAM_STDIN ){ - /* Forbidden */ - return -1; - }else if( pData->iType == JX9_IO_STREAM_OUTPUT ){ - jx9_output_consumer *pCons = &pData->x.sConsumer; - int rc; - /* Call the vm output consumer */ - rc = pCons->xConsumer(pBuf, (unsigned int)nWrite, pCons->pUserData); - if( rc == JX9_ABORT ){ - return -1; - } - return nWrite; - } -#ifdef __WINNT__ - { - DWORD nWr; - BOOL rc; - rc = WriteFile(pData->x.pHandle, pBuf, (DWORD)nWrite, &nWr, 0); - if( !rc ){ - /* IO error */ - return -1; - } - return (jx9_int64)nWr; - } -#elif defined(__UNIXES__) - { - ssize_t nWr; - int fd; - fd = SX_PTR_TO_INT(pData->x.pHandle); - nWr = write(fd, pBuf, (size_t)nWrite); - if( nWr < 1 ){ - return -1; - } - return (jx9_int64)nWr; - } -#else - return -1; -#endif -} -/* void (*xClose)(void *) */ -static void JX9StreamData_Close(void *pHandle) -{ - jx9_stream_data *pData = (jx9_stream_data *)pHandle; - jx9_vm *pVm; - if( pData == 0 ){ - return; - } - pVm = pData->pVm; - /* Free the instance */ - SyMemBackendFree(&pVm->sAllocator, pData); -} -/* Export the jx9:// stream */ -static const jx9_io_stream sjx9Stream = { - "jx9", - JX9_IO_STREAM_VERSION, - JX9StreamData_Open, /* xOpen */ - 0, /* xOpenDir */ - JX9StreamData_Close, /* xClose */ - 0, /* xCloseDir */ - JX9StreamData_Read, /* xRead */ - 0, /* xReadDir */ - JX9StreamData_Write, /* xWrite */ - 0, /* xSeek */ - 0, /* xLock */ - 0, /* xRewindDir */ - 0, /* xTell */ - 0, /* xTrunc */ - 0, /* xSeek */ - 0 /* xStat */ -}; -#endif /* JX9_DISABLE_DISK_IO */ -/* - * Return TRUE if we are dealing with the jx9:// stream. - * FALSE otherwise. - */ -static int is_jx9_stream(const jx9_io_stream *pStream) -{ -#ifndef JX9_DISABLE_DISK_IO - return pStream == &sjx9Stream; -#else - SXUNUSED(pStream); /* cc warning */ - return 0; -#endif /* JX9_DISABLE_DISK_IO */ -} - -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* - * Export the IO routines defined above and the built-in IO streams - * [i.e: file://, jx9://]. - * Note: - * If the engine is compiled with the JX9_DISABLE_BUILTIN_FUNC directive - * defined then this function is a no-op. - */ -JX9_PRIVATE sxi32 jx9RegisterIORoutine(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC - /* VFS functions */ - static const jx9_builtin_func aVfsFunc[] = { - {"chdir", jx9Vfs_chdir }, - {"chroot", jx9Vfs_chroot }, - {"getcwd", jx9Vfs_getcwd }, - {"rmdir", jx9Vfs_rmdir }, - {"is_dir", jx9Vfs_is_dir }, - {"mkdir", jx9Vfs_mkdir }, - {"rename", jx9Vfs_rename }, - {"realpath", jx9Vfs_realpath}, - {"sleep", jx9Vfs_sleep }, - {"usleep", jx9Vfs_usleep }, - {"unlink", jx9Vfs_unlink }, - {"delete", jx9Vfs_unlink }, - {"chmod", jx9Vfs_chmod }, - {"chown", jx9Vfs_chown }, - {"chgrp", jx9Vfs_chgrp }, - {"disk_free_space", jx9Vfs_disk_free_space }, - {"disk_total_space", jx9Vfs_disk_total_space}, - {"file_exists", jx9Vfs_file_exists }, - {"filesize", jx9Vfs_file_size }, - {"fileatime", jx9Vfs_file_atime }, - {"filemtime", jx9Vfs_file_mtime }, - {"filectime", jx9Vfs_file_ctime }, - {"is_file", jx9Vfs_is_file }, - {"is_link", jx9Vfs_is_link }, - {"is_readable", jx9Vfs_is_readable }, - {"is_writable", jx9Vfs_is_writable }, - {"is_executable", jx9Vfs_is_executable}, - {"filetype", jx9Vfs_filetype }, - {"stat", jx9Vfs_stat }, - {"lstat", jx9Vfs_lstat }, - {"getenv", jx9Vfs_getenv }, - {"setenv", jx9Vfs_putenv }, - {"putenv", jx9Vfs_putenv }, - {"touch", jx9Vfs_touch }, - {"link", jx9Vfs_link }, - {"symlink", jx9Vfs_symlink }, - {"umask", jx9Vfs_umask }, - {"sys_get_temp_dir", jx9Vfs_sys_get_temp_dir }, - {"get_current_user", jx9Vfs_get_current_user }, - {"getpid", jx9Vfs_getmypid }, - {"getuid", jx9Vfs_getmyuid }, - {"getgid", jx9Vfs_getmygid }, - {"uname", jx9Vfs_uname}, - /* Path processing */ - {"dirname", jx9Builtin_dirname }, - {"basename", jx9Builtin_basename }, - {"pathinfo", jx9Builtin_pathinfo }, - {"strglob", jx9Builtin_strglob }, - {"fnmatch", jx9Builtin_fnmatch }, - /* ZIP processing */ - {"zip_open", jx9Builtin_zip_open }, - {"zip_close", jx9Builtin_zip_close}, - {"zip_read", jx9Builtin_zip_read }, - {"zip_entry_open", jx9Builtin_zip_entry_open }, - {"zip_entry_close", jx9Builtin_zip_entry_close}, - {"zip_entry_name", jx9Builtin_zip_entry_name }, - {"zip_entry_filesize", jx9Builtin_zip_entry_filesize }, - {"zip_entry_compressedsize", jx9Builtin_zip_entry_compressedsize }, - {"zip_entry_read", jx9Builtin_zip_entry_read }, - {"zip_entry_reset_cursor", jx9Builtin_zip_entry_reset_cursor}, - {"zip_entry_compressionmethod", jx9Builtin_zip_entry_compressionmethod} - }; - /* IO stream functions */ - static const jx9_builtin_func aIOFunc[] = { - {"ftruncate", jx9Builtin_ftruncate }, - {"fseek", jx9Builtin_fseek }, - {"ftell", jx9Builtin_ftell }, - {"rewind", jx9Builtin_rewind }, - {"fflush", jx9Builtin_fflush }, - {"feof", jx9Builtin_feof }, - {"fgetc", jx9Builtin_fgetc }, - {"fgets", jx9Builtin_fgets }, - {"fread", jx9Builtin_fread }, - {"fgetcsv", jx9Builtin_fgetcsv}, - {"fgetss", jx9Builtin_fgetss }, - {"readdir", jx9Builtin_readdir}, - {"rewinddir", jx9Builtin_rewinddir }, - {"closedir", jx9Builtin_closedir}, - {"opendir", jx9Builtin_opendir }, - {"readfile", jx9Builtin_readfile}, - {"file_get_contents", jx9Builtin_file_get_contents}, - {"file_put_contents", jx9Builtin_file_put_contents}, - {"file", jx9Builtin_file }, - {"copy", jx9Builtin_copy }, - {"fstat", jx9Builtin_fstat }, - {"fwrite", jx9Builtin_fwrite }, - {"fputs", jx9Builtin_fwrite }, - {"flock", jx9Builtin_flock }, - {"fclose", jx9Builtin_fclose }, - {"fopen", jx9Builtin_fopen }, - {"fpassthru", jx9Builtin_fpassthru }, - {"fputcsv", jx9Builtin_fputcsv }, - {"fprintf", jx9Builtin_fprintf }, -#if !defined(JX9_DISABLE_HASH_FUNC) - {"md5_file", jx9Builtin_md5_file}, - {"sha1_file", jx9Builtin_sha1_file}, -#endif /* JX9_DISABLE_HASH_FUNC */ - {"parse_ini_file", jx9Builtin_parse_ini_file}, - {"vfprintf", jx9Builtin_vfprintf} - }; - const jx9_io_stream *pFileStream = 0; - sxu32 n = 0; - /* Register the functions defined above */ - for( n = 0 ; n < SX_ARRAYSIZE(aVfsFunc) ; ++n ){ - jx9_create_function(&(*pVm), aVfsFunc[n].zName, aVfsFunc[n].xFunc, (void *)pVm->pEngine->pVfs); - } - for( n = 0 ; n < SX_ARRAYSIZE(aIOFunc) ; ++n ){ - jx9_create_function(&(*pVm), aIOFunc[n].zName, aIOFunc[n].xFunc, pVm); - } -#ifndef JX9_DISABLE_DISK_IO - /* Register the file stream if available */ -#ifdef __WINNT__ - pFileStream = &sWinFileStream; -#elif defined(__UNIXES__) - pFileStream = &sUnixFileStream; -#endif - /* Install the jx9:// stream */ - jx9_vm_config(pVm, JX9_VM_CONFIG_IO_STREAM, &sjx9Stream); -#endif /* JX9_DISABLE_DISK_IO */ - if( pFileStream ){ - /* Install the file:// stream */ - jx9_vm_config(pVm, JX9_VM_CONFIG_IO_STREAM, pFileStream); - } -#else - SXUNUSED(pVm); /* cc warning */ -#endif /* JX9_DISABLE_BUILTIN_FUNC */ - return SXRET_OK; -} -/* - * Export the STDIN handle. - */ -JX9_PRIVATE void * jx9ExportStdin(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_DISK_IO - if( pVm->pStdin == 0 ){ - io_private *pIn; - /* Allocate an IO private instance */ - pIn = (io_private *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(io_private)); - if( pIn == 0 ){ - return 0; - } - InitIOPrivate(pVm, &sjx9Stream, pIn); - /* Initialize the handle */ - pIn->pHandle = JX9StreamDataInit(pVm, JX9_IO_STREAM_STDIN); - /* Install the STDIN stream */ - pVm->pStdin = pIn; - return pIn; - }else{ - /* NULL or STDIN */ - return pVm->pStdin; - } -#else - return 0; -#endif -#else - SXUNUSED(pVm); /* cc warning */ - return 0; -#endif -} -/* - * Export the STDOUT handle. - */ -JX9_PRIVATE void * jx9ExportStdout(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_DISK_IO - if( pVm->pStdout == 0 ){ - io_private *pOut; - /* Allocate an IO private instance */ - pOut = (io_private *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(io_private)); - if( pOut == 0 ){ - return 0; - } - InitIOPrivate(pVm, &sjx9Stream, pOut); - /* Initialize the handle */ - pOut->pHandle = JX9StreamDataInit(pVm, JX9_IO_STREAM_STDOUT); - /* Install the STDOUT stream */ - pVm->pStdout = pOut; - return pOut; - }else{ - /* NULL or STDOUT */ - return pVm->pStdout; - } -#else - return 0; -#endif -#else - SXUNUSED(pVm); /* cc warning */ - return 0; -#endif -} -/* - * Export the STDERR handle. - */ -JX9_PRIVATE void * jx9ExportStderr(jx9_vm *pVm) -{ -#ifndef JX9_DISABLE_BUILTIN_FUNC -#ifndef JX9_DISABLE_DISK_IO - if( pVm->pStderr == 0 ){ - io_private *pErr; - /* Allocate an IO private instance */ - pErr = (io_private *)SyMemBackendAlloc(&pVm->sAllocator, sizeof(io_private)); - if( pErr == 0 ){ - return 0; - } - InitIOPrivate(pVm, &sjx9Stream, pErr); - /* Initialize the handle */ - pErr->pHandle = JX9StreamDataInit(pVm, JX9_IO_STREAM_STDERR); - /* Install the STDERR stream */ - pVm->pStderr = pErr; - return pErr; - }else{ - /* NULL or STDERR */ - return pVm->pStderr; - } -#else - return 0; -#endif -#else - SXUNUSED(pVm); /* cc warning */ - return 0; -#endif -} - -/* - * ---------------------------------------------------------- - * File: jx9_vm.c - * MD5: beca4be65a9a49c932c356d7680034c9 - * ---------------------------------------------------------- - */ -/* - * Symisc JX9: A Highly Efficient Embeddable Scripting Engine Based on JSON. - * Copyright (C) 2012-2013, Symisc Systems http://jx9.symisc.net/ - * Version 1.7.2 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://jx9.symisc.net/ - */ - /* $SymiscID: jx9_vm.c v1.0 FreeBSD 2012-12-09 00:19 stable $ */ -#ifndef JX9_AMALGAMATION -#include "jx9Int.h" -#endif -/* - * The code in this file implements execution method of the JX9 Virtual Machine. - * The JX9 compiler (implemented in 'compiler.c' and 'parse.c') generates a bytecode program - * which is then executed by the virtual machine implemented here to do the work of the JX9 - * statements. - * JX9 bytecode programs are similar in form to assembly language. The program consists - * of a linear sequence of operations .Each operation has an opcode and 3 operands. - * Operands P1 and P2 are integers where the first is signed while the second is unsigned. - * Operand P3 is an arbitrary pointer specific to each instruction. The P2 operand is usually - * the jump destination used by the OP_JMP, OP_JZ, OP_JNZ, ... instructions. - * Opcodes will typically ignore one or more operands. Many opcodes ignore all three operands. - * Computation results are stored on a stack. Each entry on the stack is of type jx9_value. - * JX9 uses the jx9_value object to represent all values that can be stored in a JX9 variable. - * Since JX9 uses dynamic typing for the values it stores. Values stored in jx9_value objects - * can be integers, floating point values, strings, arrays, object instances (object in the JX9 jargon) - * and so on. - * Internally, the JX9 virtual machine manipulates nearly all values as jx9_values structures. - * Each jx9_value may cache multiple representations(string, integer etc.) of the same value. - * An implicit conversion from one type to the other occurs as necessary. - * Most of the code in this file is taken up by the [VmByteCodeExec()] function which does - * the work of interpreting a JX9 bytecode program. But other routines are also provided - * to help in building up a program instruction by instruction. - */ -/* - * Each active virtual machine frame is represented by an instance - * of the following structure. - * VM Frame hold local variables and other stuff related to function call. - */ -struct VmFrame -{ - VmFrame *pParent; /* Parent frame or NULL if global scope */ - void *pUserData; /* Upper layer private data associated with this frame */ - SySet sLocal; /* Local variables container (VmSlot instance) */ - jx9_vm *pVm; /* VM that own this frame */ - SyHash hVar; /* Variable hashtable for fast lookup */ - SySet sArg; /* Function arguments container */ - sxi32 iFlags; /* Frame configuration flags (See below)*/ - sxu32 iExceptionJump; /* Exception jump destination */ -}; -/* - * When a user defined variable is garbage collected, memory object index - * is stored in an instance of the following structure and put in the free object - * table so that it can be reused again without allocating a new memory object. - */ -typedef struct VmSlot VmSlot; -struct VmSlot -{ - sxu32 nIdx; /* Index in pVm->aMemObj[] */ - void *pUserData; /* Upper-layer private data */ -}; -/* - * Each parsed URI is recorded and stored in an instance of the following structure. - * This structure and it's related routines are taken verbatim from the xHT project - * [A modern embeddable HTTP engine implementing all the RFC2616 methods] - * the xHT project is developed internally by Symisc Systems. - */ -typedef struct SyhttpUri SyhttpUri; -struct SyhttpUri -{ - SyString sHost; /* Hostname or IP address */ - SyString sPort; /* Port number */ - SyString sPath; /* Mandatory resource path passed verbatim (Not decoded) */ - SyString sQuery; /* Query part */ - SyString sFragment; /* Fragment part */ - SyString sScheme; /* Scheme */ - SyString sUser; /* Username */ - SyString sPass; /* Password */ - SyString sRaw; /* Raw URI */ -}; -/* - * An instance of the following structure is used to record all MIME headers seen - * during a HTTP interaction. - * This structure and it's related routines are taken verbatim from the xHT project - * [A modern embeddable HTTP engine implementing all the RFC2616 methods] - * the xHT project is developed internally by Symisc Systems. - */ -typedef struct SyhttpHeader SyhttpHeader; -struct SyhttpHeader -{ - SyString sName; /* Header name [i.e:"Content-Type", "Host", "User-Agent"]. NOT NUL TERMINATED */ - SyString sValue; /* Header values [i.e: "text/html"]. NOT NUL TERMINATED */ -}; -/* - * Supported HTTP methods. - */ -#define HTTP_METHOD_GET 1 /* GET */ -#define HTTP_METHOD_HEAD 2 /* HEAD */ -#define HTTP_METHOD_POST 3 /* POST */ -#define HTTP_METHOD_PUT 4 /* PUT */ -#define HTTP_METHOD_OTHR 5 /* Other HTTP methods [i.e: DELETE, TRACE, OPTIONS...]*/ -/* - * Supported HTTP protocol version. - */ -#define HTTP_PROTO_10 1 /* HTTP/1.0 */ -#define HTTP_PROTO_11 2 /* HTTP/1.1 */ -/* - * Register a constant and it's associated expansion callback so that - * it can be expanded from the target JX9 program. - * The constant expansion mechanism under JX9 is extremely powerful yet - * simple and work as follows: - * Each registered constant have a C procedure associated with it. - * This procedure known as the constant expansion callback is responsible - * of expanding the invoked constant to the desired value, for example: - * The C procedure associated with the "__PI__" constant expands to 3.14 (the value of PI). - * The "__OS__" constant procedure expands to the name of the host Operating Systems - * (Windows, Linux, ...) and so on. - * Please refer to the official documentation for additional information. - */ -JX9_PRIVATE sxi32 jx9VmRegisterConstant( - jx9_vm *pVm, /* Target VM */ - const SyString *pName, /* Constant name */ - ProcConstant xExpand, /* Constant expansion callback */ - void *pUserData /* Last argument to xExpand() */ - ) -{ - jx9_constant *pCons; - SyHashEntry *pEntry; - char *zDupName; - sxi32 rc; - pEntry = SyHashGet(&pVm->hConstant, (const void *)pName->zString, pName->nByte); - if( pEntry ){ - /* Overwrite the old definition and return immediately */ - pCons = (jx9_constant *)pEntry->pUserData; - pCons->xExpand = xExpand; - pCons->pUserData = pUserData; - return SXRET_OK; - } - /* Allocate a new constant instance */ - pCons = (jx9_constant *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_constant)); - if( pCons == 0 ){ - return 0; - } - /* Duplicate constant name */ - zDupName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte); - if( zDupName == 0 ){ - SyMemBackendPoolFree(&pVm->sAllocator, pCons); - return 0; - } - /* Install the constant */ - SyStringInitFromBuf(&pCons->sName, zDupName, pName->nByte); - pCons->xExpand = xExpand; - pCons->pUserData = pUserData; - rc = SyHashInsert(&pVm->hConstant, (const void *)zDupName, SyStringLength(&pCons->sName), pCons); - if( rc != SXRET_OK ){ - SyMemBackendFree(&pVm->sAllocator, zDupName); - SyMemBackendPoolFree(&pVm->sAllocator, pCons); - return rc; - } - /* All done, constant can be invoked from JX9 code */ - return SXRET_OK; -} -/* - * Allocate a new foreign function instance. - * This function return SXRET_OK on success. Any other - * return value indicates failure. - * Please refer to the official documentation for an introduction to - * the foreign function mechanism. - */ -static sxi32 jx9NewForeignFunction( - jx9_vm *pVm, /* Target VM */ - const SyString *pName, /* Foreign function name */ - ProcHostFunction xFunc, /* Foreign function implementation */ - void *pUserData, /* Foreign function private data */ - jx9_user_func **ppOut /* OUT: VM image of the foreign function */ - ) -{ - jx9_user_func *pFunc; - char *zDup; - /* Allocate a new user function */ - pFunc = (jx9_user_func *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_user_func)); - if( pFunc == 0 ){ - return SXERR_MEM; - } - /* Duplicate function name */ - zDup = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte); - if( zDup == 0 ){ - SyMemBackendPoolFree(&pVm->sAllocator, pFunc); - return SXERR_MEM; - } - /* Zero the structure */ - SyZero(pFunc, sizeof(jx9_user_func)); - /* Initialize structure fields */ - SyStringInitFromBuf(&pFunc->sName, zDup, pName->nByte); - pFunc->pVm = pVm; - pFunc->xFunc = xFunc; - pFunc->pUserData = pUserData; - SySetInit(&pFunc->aAux, &pVm->sAllocator, sizeof(jx9_aux_data)); - /* Write a pointer to the new function */ - *ppOut = pFunc; - return SXRET_OK; -} -/* - * Install a foreign function and it's associated callback so that - * it can be invoked from the target JX9 code. - * This function return SXRET_OK on successful registration. Any other - * return value indicates failure. - * Please refer to the official documentation for an introduction to - * the foreign function mechanism. - */ -JX9_PRIVATE sxi32 jx9VmInstallForeignFunction( - jx9_vm *pVm, /* Target VM */ - const SyString *pName, /* Foreign function name */ - ProcHostFunction xFunc, /* Foreign function implementation */ - void *pUserData /* Foreign function private data */ - ) -{ - jx9_user_func *pFunc; - SyHashEntry *pEntry; - sxi32 rc; - /* Overwrite any previously registered function with the same name */ - pEntry = SyHashGet(&pVm->hHostFunction, pName->zString, pName->nByte); - if( pEntry ){ - pFunc = (jx9_user_func *)pEntry->pUserData; - pFunc->pUserData = pUserData; - pFunc->xFunc = xFunc; - SySetReset(&pFunc->aAux); - return SXRET_OK; - } - /* Create a new user function */ - rc = jx9NewForeignFunction(&(*pVm), &(*pName), xFunc, pUserData, &pFunc); - if( rc != SXRET_OK ){ - return rc; - } - /* Install the function in the corresponding hashtable */ - rc = SyHashInsert(&pVm->hHostFunction, SyStringData(&pFunc->sName), pName->nByte, pFunc); - if( rc != SXRET_OK ){ - SyMemBackendFree(&pVm->sAllocator, (void *)SyStringData(&pFunc->sName)); - SyMemBackendPoolFree(&pVm->sAllocator, pFunc); - return rc; - } - /* User function successfully installed */ - return SXRET_OK; -} -/* - * Initialize a VM function. - */ -JX9_PRIVATE sxi32 jx9VmInitFuncState( - jx9_vm *pVm, /* Target VM */ - jx9_vm_func *pFunc, /* Target Fucntion */ - const char *zName, /* Function name */ - sxu32 nByte, /* zName length */ - sxi32 iFlags, /* Configuration flags */ - void *pUserData /* Function private data */ - ) -{ - /* Zero the structure */ - SyZero(pFunc, sizeof(jx9_vm_func)); - /* Initialize structure fields */ - /* Arguments container */ - SySetInit(&pFunc->aArgs, &pVm->sAllocator, sizeof(jx9_vm_func_arg)); - /* Static variable container */ - SySetInit(&pFunc->aStatic, &pVm->sAllocator, sizeof(jx9_vm_func_static_var)); - /* Bytecode container */ - SySetInit(&pFunc->aByteCode, &pVm->sAllocator, sizeof(VmInstr)); - /* Preallocate some instruction slots */ - SySetAlloc(&pFunc->aByteCode, 0x10); - pFunc->iFlags = iFlags; - pFunc->pUserData = pUserData; - SyStringInitFromBuf(&pFunc->sName, zName, nByte); - return SXRET_OK; -} -/* - * Install a user defined function in the corresponding VM container. - */ -JX9_PRIVATE sxi32 jx9VmInstallUserFunction( - jx9_vm *pVm, /* Target VM */ - jx9_vm_func *pFunc, /* Target function */ - SyString *pName /* Function name */ - ) -{ - SyHashEntry *pEntry; - sxi32 rc; - if( pName == 0 ){ - /* Use the built-in name */ - pName = &pFunc->sName; - } - /* Check for duplicates (functions with the same name) first */ - pEntry = SyHashGet(&pVm->hFunction, pName->zString, pName->nByte); - if( pEntry ){ - jx9_vm_func *pLink = (jx9_vm_func *)pEntry->pUserData; - if( pLink != pFunc ){ - /* Link */ - pFunc->pNextName = pLink; - pEntry->pUserData = pFunc; - } - return SXRET_OK; - } - /* First time seen */ - pFunc->pNextName = 0; - rc = SyHashInsert(&pVm->hFunction, pName->zString, pName->nByte, pFunc); - return rc; -} -/* - * Instruction builder interface. - */ -JX9_PRIVATE sxi32 jx9VmEmitInstr( - jx9_vm *pVm, /* Target VM */ - sxi32 iOp, /* Operation to perform */ - sxi32 iP1, /* First operand */ - sxu32 iP2, /* Second operand */ - void *p3, /* Third operand */ - sxu32 *pIndex /* Instruction index. NULL otherwise */ - ) -{ - VmInstr sInstr; - sxi32 rc; - /* Fill the VM instruction */ - sInstr.iOp = (sxu8)iOp; - sInstr.iP1 = iP1; - sInstr.iP2 = iP2; - sInstr.p3 = p3; - if( pIndex ){ - /* Instruction index in the bytecode array */ - *pIndex = SySetUsed(pVm->pByteContainer); - } - /* Finally, record the instruction */ - rc = SySetPut(pVm->pByteContainer, (const void *)&sInstr); - if( rc != SXRET_OK ){ - jx9GenCompileError(&pVm->sCodeGen, E_ERROR, 1, "Fatal, Cannot emit instruction due to a memory failure"); - /* Fall throw */ - } - return rc; -} -/* - * Swap the current bytecode container with the given one. - */ -JX9_PRIVATE sxi32 jx9VmSetByteCodeContainer(jx9_vm *pVm, SySet *pContainer) -{ - if( pContainer == 0 ){ - /* Point to the default container */ - pVm->pByteContainer = &pVm->aByteCode; - }else{ - /* Change container */ - pVm->pByteContainer = &(*pContainer); - } - return SXRET_OK; -} -/* - * Return the current bytecode container. - */ -JX9_PRIVATE SySet * jx9VmGetByteCodeContainer(jx9_vm *pVm) -{ - return pVm->pByteContainer; -} -/* - * Extract the VM instruction rooted at nIndex. - */ -JX9_PRIVATE VmInstr * jx9VmGetInstr(jx9_vm *pVm, sxu32 nIndex) -{ - VmInstr *pInstr; - pInstr = (VmInstr *)SySetAt(pVm->pByteContainer, nIndex); - return pInstr; -} -/* - * Return the total number of VM instructions recorded so far. - */ -JX9_PRIVATE sxu32 jx9VmInstrLength(jx9_vm *pVm) -{ - return SySetUsed(pVm->pByteContainer); -} -/* - * Pop the last VM instruction. - */ -JX9_PRIVATE VmInstr * jx9VmPopInstr(jx9_vm *pVm) -{ - return (VmInstr *)SySetPop(pVm->pByteContainer); -} -/* - * Peek the last VM instruction. - */ -JX9_PRIVATE VmInstr * jx9VmPeekInstr(jx9_vm *pVm) -{ - return (VmInstr *)SySetPeek(pVm->pByteContainer); -} -/* - * Allocate a new virtual machine frame. - */ -static VmFrame * VmNewFrame( - jx9_vm *pVm, /* Target VM */ - void *pUserData /* Upper-layer private data */ - ) -{ - VmFrame *pFrame; - /* Allocate a new vm frame */ - pFrame = (VmFrame *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(VmFrame)); - if( pFrame == 0 ){ - return 0; - } - /* Zero the structure */ - SyZero(pFrame, sizeof(VmFrame)); - /* Initialize frame fields */ - pFrame->pUserData = pUserData; - pFrame->pVm = pVm; - SyHashInit(&pFrame->hVar, &pVm->sAllocator, 0, 0); - SySetInit(&pFrame->sArg, &pVm->sAllocator, sizeof(VmSlot)); - SySetInit(&pFrame->sLocal, &pVm->sAllocator, sizeof(VmSlot)); - return pFrame; -} -/* - * Enter a VM frame. - */ -static sxi32 VmEnterFrame( - jx9_vm *pVm, /* Target VM */ - void *pUserData, /* Upper-layer private data */ - VmFrame **ppFrame /* OUT: Top most active frame */ - ) -{ - VmFrame *pFrame; - /* Allocate a new frame */ - pFrame = VmNewFrame(&(*pVm), pUserData); - if( pFrame == 0 ){ - return SXERR_MEM; - } - /* Link to the list of active VM frame */ - pFrame->pParent = pVm->pFrame; - pVm->pFrame = pFrame; - if( ppFrame ){ - /* Write a pointer to the new VM frame */ - *ppFrame = pFrame; - } - return SXRET_OK; -} -/* - * Link a foreign variable with the TOP most active frame. - * Refer to the JX9_OP_UPLINK instruction implementation for more - * information. - */ -static sxi32 VmFrameLink(jx9_vm *pVm,SyString *pName) -{ - VmFrame *pTarget, *pFrame; - SyHashEntry *pEntry = 0; - sxi32 rc; - /* Point to the upper frame */ - pFrame = pVm->pFrame; - pTarget = pFrame; - pFrame = pTarget->pParent; - while( pFrame ){ - /* Query the current frame */ - pEntry = SyHashGet(&pFrame->hVar, (const void *)pName->zString, pName->nByte); - if( pEntry ){ - /* Variable found */ - break; - } - /* Point to the upper frame */ - pFrame = pFrame->pParent; - } - if( pEntry == 0 ){ - /* Inexistant variable */ - return SXERR_NOTFOUND; - } - /* Link to the current frame */ - rc = SyHashInsert(&pTarget->hVar, pEntry->pKey, pEntry->nKeyLen, pEntry->pUserData); - return rc; -} -/* - * Leave the top-most active frame. - */ -static void VmLeaveFrame(jx9_vm *pVm) -{ - VmFrame *pFrame = pVm->pFrame; - if( pFrame ){ - /* Unlink from the list of active VM frame */ - pVm->pFrame = pFrame->pParent; - if( pFrame->pParent ){ - VmSlot *aSlot; - sxu32 n; - /* Restore local variable to the free pool so that they can be reused again */ - aSlot = (VmSlot *)SySetBasePtr(&pFrame->sLocal); - for(n = 0 ; n < SySetUsed(&pFrame->sLocal) ; ++n ){ - /* Unset the local variable */ - jx9VmUnsetMemObj(&(*pVm), aSlot[n].nIdx); - } - } - /* Release internal containers */ - SyHashRelease(&pFrame->hVar); - SySetRelease(&pFrame->sArg); - SySetRelease(&pFrame->sLocal); - /* Release the whole structure */ - SyMemBackendPoolFree(&pVm->sAllocator, pFrame); - } -} -/* - * Compare two functions signature and return the comparison result. - */ -static int VmOverloadCompare(SyString *pFirst, SyString *pSecond) -{ - const char *zSend = &pSecond->zString[pSecond->nByte]; - const char *zFend = &pFirst->zString[pFirst->nByte]; - const char *zSin = pSecond->zString; - const char *zFin = pFirst->zString; - const char *zPtr = zFin; - for(;;){ - if( zFin >= zFend || zSin >= zSend ){ - break; - } - if( zFin[0] != zSin[0] ){ - /* mismatch */ - break; - } - zFin++; - zSin++; - } - return (int)(zFin-zPtr); -} -/* - * Select the appropriate VM function for the current call context. - * This is the implementation of the powerful 'function overloading' feature - * introduced by the version 2 of the JX9 engine. - * Refer to the official documentation for more information. - */ -static jx9_vm_func * VmOverload( - jx9_vm *pVm, /* Target VM */ - jx9_vm_func *pList, /* Linked list of candidates for overloading */ - jx9_value *aArg, /* Array of passed arguments */ - int nArg /* Total number of passed arguments */ - ) -{ - int iTarget, i, j, iCur, iMax; - jx9_vm_func *apSet[10]; /* Maximum number of candidates */ - jx9_vm_func *pLink; - SyString sArgSig; - SyBlob sSig; - - pLink = pList; - i = 0; - /* Put functions expecting the same number of passed arguments */ - while( i < (int)SX_ARRAYSIZE(apSet) ){ - if( pLink == 0 ){ - break; - } - if( (int)SySetUsed(&pLink->aArgs) == nArg ){ - /* Candidate for overloading */ - apSet[i++] = pLink; - } - /* Point to the next entry */ - pLink = pLink->pNextName; - } - if( i < 1 ){ - /* No candidates, return the head of the list */ - return pList; - } - if( nArg < 1 || i < 2 ){ - /* Return the only candidate */ - return apSet[0]; - } - /* Calculate function signature */ - SyBlobInit(&sSig, &pVm->sAllocator); - for( j = 0 ; j < nArg ; j++ ){ - int c = 'n'; /* null */ - if( aArg[j].iFlags & MEMOBJ_HASHMAP ){ - /* Hashmap */ - c = 'h'; - }else if( aArg[j].iFlags & MEMOBJ_BOOL ){ - /* bool */ - c = 'b'; - }else if( aArg[j].iFlags & MEMOBJ_INT ){ - /* int */ - c = 'i'; - }else if( aArg[j].iFlags & MEMOBJ_STRING ){ - /* String */ - c = 's'; - }else if( aArg[j].iFlags & MEMOBJ_REAL ){ - /* Float */ - c = 'f'; - } - if( c > 0 ){ - SyBlobAppend(&sSig, (const void *)&c, sizeof(char)); - } - } - SyStringInitFromBuf(&sArgSig, SyBlobData(&sSig), SyBlobLength(&sSig)); - iTarget = 0; - iMax = -1; - /* Select the appropriate function */ - for( j = 0 ; j < i ; j++ ){ - /* Compare the two signatures */ - iCur = VmOverloadCompare(&sArgSig, &apSet[j]->sSignature); - if( iCur > iMax ){ - iMax = iCur; - iTarget = j; - } - } - SyBlobRelease(&sSig); - /* Appropriate function for the current call context */ - return apSet[iTarget]; -} -/* - * Dummy read-only buffer used for slot reservation. - */ -static const char zDummy[sizeof(jx9_value)] = { 0 }; /* Must be >= sizeof(jx9_value) */ -/* - * Reserve a constant memory object. - * Return a pointer to the raw jx9_value on success. NULL on failure. - */ -JX9_PRIVATE jx9_value * jx9VmReserveConstObj(jx9_vm *pVm, sxu32 *pIndex) -{ - jx9_value *pObj; - sxi32 rc; - if( pIndex ){ - /* Object index in the object table */ - *pIndex = SySetUsed(&pVm->aLitObj); - } - /* Reserve a slot for the new object */ - rc = SySetPut(&pVm->aLitObj, (const void *)zDummy); - if( rc != SXRET_OK ){ - /* If the supplied memory subsystem is so sick that we are unable to allocate - * a tiny chunk of memory, there is no much we can do here. - */ - return 0; - } - pObj = (jx9_value *)SySetPeek(&pVm->aLitObj); - return pObj; -} -/* - * Reserve a memory object. - * Return a pointer to the raw jx9_value on success. NULL on failure. - */ -static jx9_value * VmReserveMemObj(jx9_vm *pVm, sxu32 *pIndex) -{ - jx9_value *pObj; - sxi32 rc; - if( pIndex ){ - /* Object index in the object table */ - *pIndex = SySetUsed(&pVm->aMemObj); - } - /* Reserve a slot for the new object */ - rc = SySetPut(&pVm->aMemObj, (const void *)zDummy); - if( rc != SXRET_OK ){ - /* If the supplied memory subsystem is so sick that we are unable to allocate - * a tiny chunk of memory, there is no much we can do here. - */ - return 0; - } - pObj = (jx9_value *)SySetPeek(&pVm->aMemObj); - return pObj; -} -/* Forward declaration */ -static sxi32 VmEvalChunk(jx9_vm *pVm, jx9_context *pCtx, SyString *pChunk, int iFlags, int bTrueReturn); -/* - * Built-in functions that cannot be implemented directly as foreign functions. - */ -#define JX9_BUILTIN_LIB \ - "function scandir(string $directory, int $sort_order = SCANDIR_SORT_ASCENDING)"\ - "{"\ - " if( func_num_args() < 1 ){ return FALSE; }"\ - " $aDir = [];"\ - " $pHandle = opendir($directory);"\ - " if( $pHandle == FALSE ){ return FALSE; }"\ - " while(FALSE !== ($pEntry = readdir($pHandle)) ){"\ - " $aDir[] = $pEntry;"\ - " }"\ - " closedir($pHandle);"\ - " if( $sort_order == SCANDIR_SORT_DESCENDING ){"\ - " rsort($aDir);"\ - " }else if( $sort_order == SCANDIR_SORT_ASCENDING ){"\ - " sort($aDir);"\ - " }"\ - " return $aDir;"\ - "}"\ - "function glob(string $pattern, int $iFlags = 0){"\ - "/* Open the target directory */"\ - "$zDir = dirname($pattern);"\ - "if(!is_string($zDir) ){ $zDir = './'; }"\ - "$pHandle = opendir($zDir);"\ - "if( $pHandle == FALSE ){"\ - " /* IO error while opening the current directory, return FALSE */"\ - " return FALSE;"\ - "}"\ - "$pattern = basename($pattern);"\ - "$pArray = []; /* Empty array */"\ - "/* Loop throw available entries */"\ - "while( FALSE !== ($pEntry = readdir($pHandle)) ){"\ - " /* Use the built-in strglob function which is a Symisc eXtension for wildcard comparison*/"\ - " $rc = strglob($pattern, $pEntry);"\ - " if( $rc ){"\ - " if( is_dir($pEntry) ){"\ - " if( $iFlags & GLOB_MARK ){"\ - " /* Adds a slash to each directory returned */"\ - " $pEntry .= DIRECTORY_SEPARATOR;"\ - " }"\ - " }else if( $iFlags & GLOB_ONLYDIR ){"\ - " /* Not a directory, ignore */"\ - " continue;"\ - " }"\ - " /* Add the entry */"\ - " $pArray[] = $pEntry;"\ - " }"\ - " }"\ - "/* Close the handle */"\ - "closedir($pHandle);"\ - "if( ($iFlags & GLOB_NOSORT) == 0 ){"\ - " /* Sort the array */"\ - " sort($pArray);"\ - "}"\ - "if( ($iFlags & GLOB_NOCHECK) && sizeof($pArray) < 1 ){"\ - " /* Return the search pattern if no files matching were found */"\ - " $pArray[] = $pattern;"\ - "}"\ - "/* Return the created array */"\ - "return $pArray;"\ - "}"\ - "/* Creates a temporary file */"\ - "function tmpfile(){"\ - " /* Extract the temp directory */"\ - " $zTempDir = sys_get_temp_dir();"\ - " if( strlen($zTempDir) < 1 ){"\ - " /* Use the current dir */"\ - " $zTempDir = '.';"\ - " }"\ - " /* Create the file */"\ - " $pHandle = fopen($zTempDir.DIRECTORY_SEPARATOR.'JX9'.rand_str(12), 'w+');"\ - " return $pHandle;"\ - "}"\ - "/* Creates a temporary filename */"\ - "function tempnam(string $zDir = sys_get_temp_dir() /* Symisc eXtension */, string $zPrefix = 'JX9')"\ - "{"\ - " return $zDir.DIRECTORY_SEPARATOR.$zPrefix.rand_str(12);"\ - "}"\ - "function max(){"\ - " $pArgs = func_get_args();"\ - " if( sizeof($pArgs) < 1 ){"\ - " return null;"\ - " }"\ - " if( sizeof($pArgs) < 2 ){"\ - " $pArg = $pArgs[0];"\ - " if( !is_array($pArg) ){"\ - " return $pArg; "\ - " }"\ - " if( sizeof($pArg) < 1 ){"\ - " return null;"\ - " }"\ - " $pArg = array_copy($pArgs[0]);"\ - " reset($pArg);"\ - " $max = current($pArg);"\ - " while( FALSE !== ($val = next($pArg)) ){"\ - " if( $val > $max ){"\ - " $max = $val;"\ - " }"\ - " }"\ - " return $max;"\ - " }"\ - " $max = $pArgs[0];"\ - " for( $i = 1; $i < sizeof($pArgs) ; ++$i ){"\ - " $val = $pArgs[$i];"\ - "if( $val > $max ){"\ - " $max = $val;"\ - "}"\ - " }"\ - " return $max;"\ - "}"\ - "function min(){"\ - " $pArgs = func_get_args();"\ - " if( sizeof($pArgs) < 1 ){"\ - " return null;"\ - " }"\ - " if( sizeof($pArgs) < 2 ){"\ - " $pArg = $pArgs[0];"\ - " if( !is_array($pArg) ){"\ - " return $pArg; "\ - " }"\ - " if( sizeof($pArg) < 1 ){"\ - " return null;"\ - " }"\ - " $pArg = array_copy($pArgs[0]);"\ - " reset($pArg);"\ - " $min = current($pArg);"\ - " while( FALSE !== ($val = next($pArg)) ){"\ - " if( $val < $min ){"\ - " $min = $val;"\ - " }"\ - " }"\ - " return $min;"\ - " }"\ - " $min = $pArgs[0];"\ - " for( $i = 1; $i < sizeof($pArgs) ; ++$i ){"\ - " $val = $pArgs[$i];"\ - "if( $val < $min ){"\ - " $min = $val;"\ - " }"\ - " }"\ - " return $min;"\ - "}" -/* - * Initialize a freshly allocated JX9 Virtual Machine so that we can - * start compiling the target JX9 program. - */ -JX9_PRIVATE sxi32 jx9VmInit( - jx9_vm *pVm, /* Initialize this */ - jx9 *pEngine /* Master engine */ - ) -{ - SyString sBuiltin; - jx9_value *pObj; - sxi32 rc; - /* Zero the structure */ - SyZero(pVm, sizeof(jx9_vm)); - /* Initialize VM fields */ - pVm->pEngine = &(*pEngine); - SyMemBackendInitFromParent(&pVm->sAllocator, &pEngine->sAllocator); - /* Instructions containers */ - SySetInit(&pVm->aByteCode, &pVm->sAllocator, sizeof(VmInstr)); - SySetAlloc(&pVm->aByteCode, 0xFF); - pVm->pByteContainer = &pVm->aByteCode; - /* Object containers */ - SySetInit(&pVm->aMemObj, &pVm->sAllocator, sizeof(jx9_value)); - SySetAlloc(&pVm->aMemObj, 0xFF); - /* Virtual machine internal containers */ - SyBlobInit(&pVm->sConsumer, &pVm->sAllocator); - SyBlobInit(&pVm->sWorker, &pVm->sAllocator); - SyBlobInit(&pVm->sArgv, &pVm->sAllocator); - SySetInit(&pVm->aLitObj, &pVm->sAllocator, sizeof(jx9_value)); - SySetAlloc(&pVm->aLitObj, 0xFF); - SyHashInit(&pVm->hHostFunction, &pVm->sAllocator, 0, 0); - SyHashInit(&pVm->hFunction, &pVm->sAllocator, 0, 0); - SyHashInit(&pVm->hConstant, &pVm->sAllocator, 0, 0); - SyHashInit(&pVm->hSuper, &pVm->sAllocator, 0, 0); - SySetInit(&pVm->aFreeObj, &pVm->sAllocator, sizeof(VmSlot)); - /* Configuration containers */ - SySetInit(&pVm->aFiles, &pVm->sAllocator, sizeof(SyString)); - SySetInit(&pVm->aPaths, &pVm->sAllocator, sizeof(SyString)); - SySetInit(&pVm->aIncluded, &pVm->sAllocator, sizeof(SyString)); - SySetInit(&pVm->aIOstream, &pVm->sAllocator, sizeof(jx9_io_stream *)); - /* Error callbacks containers */ - jx9MemObjInit(&(*pVm), &pVm->sAssertCallback); - /* Set a default recursion limit */ -#if defined(__WINNT__) || defined(__UNIXES__) - pVm->nMaxDepth = 32; -#else - pVm->nMaxDepth = 16; -#endif - /* Default assertion flags */ - pVm->iAssertFlags = JX9_ASSERT_WARNING; /* Issue a warning for each failed assertion */ - /* PRNG context */ - SyRandomnessInit(&pVm->sPrng, 0, 0); - /* Install the null constant */ - pObj = jx9VmReserveConstObj(&(*pVm), 0); - if( pObj == 0 ){ - rc = SXERR_MEM; - goto Err; - } - jx9MemObjInit(pVm, pObj); - /* Install the boolean TRUE constant */ - pObj = jx9VmReserveConstObj(&(*pVm), 0); - if( pObj == 0 ){ - rc = SXERR_MEM; - goto Err; - } - jx9MemObjInitFromBool(pVm, pObj, 1); - /* Install the boolean FALSE constant */ - pObj = jx9VmReserveConstObj(&(*pVm), 0); - if( pObj == 0 ){ - rc = SXERR_MEM; - goto Err; - } - jx9MemObjInitFromBool(pVm, pObj, 0); - /* Create the global frame */ - rc = VmEnterFrame(&(*pVm), 0, 0); - if( rc != SXRET_OK ){ - goto Err; - } - /* Initialize the code generator */ - rc = jx9InitCodeGenerator(pVm, pEngine->xConf.xErr, pEngine->xConf.pErrData); - if( rc != SXRET_OK ){ - goto Err; - } - /* VM correctly initialized, set the magic number */ - pVm->nMagic = JX9_VM_INIT; - SyStringInitFromBuf(&sBuiltin,JX9_BUILTIN_LIB, sizeof(JX9_BUILTIN_LIB)-1); - /* Compile the built-in library */ - VmEvalChunk(&(*pVm), 0, &sBuiltin, 0, FALSE); - /* Reset the code generator */ - jx9ResetCodeGenerator(&(*pVm), pEngine->xConf.xErr, pEngine->xConf.pErrData); - return SXRET_OK; -Err: - SyMemBackendRelease(&pVm->sAllocator); - return rc; -} -/* - * Default VM output consumer callback.That is, all VM output is redirected to this - * routine which store the output in an internal blob. - * The output can be extracted later after program execution [jx9_vm_exec()] via - * the [jx9_vm_config()] interface with a configuration verb set to - * jx9VM_CONFIG_EXTRACT_OUTPUT. - * Refer to the official docurmentation for additional information. - * Note that for performance reason it's preferable to install a VM output - * consumer callback via (jx9VM_CONFIG_OUTPUT) rather than waiting for the VM - * to finish executing and extracting the output. - */ -JX9_PRIVATE sxi32 jx9VmBlobConsumer( - const void *pOut, /* VM Generated output*/ - unsigned int nLen, /* Generated output length */ - void *pUserData /* User private data */ - ) -{ - sxi32 rc; - /* Store the output in an internal BLOB */ - rc = SyBlobAppend((SyBlob *)pUserData, pOut, nLen); - return rc; -} -#define VM_STACK_GUARD 16 -/* - * Allocate a new operand stack so that we can start executing - * our compiled JX9 program. - * Return a pointer to the operand stack (array of jx9_values) - * on success. NULL (Fatal error) on failure. - */ -static jx9_value * VmNewOperandStack( - jx9_vm *pVm, /* Target VM */ - sxu32 nInstr /* Total numer of generated bytecode instructions */ - ) -{ - jx9_value *pStack; - /* No instruction ever pushes more than a single element onto the - ** stack and the stack never grows on successive executions of the - ** same loop. So the total number of instructions is an upper bound - ** on the maximum stack depth required. - ** - ** Allocation all the stack space we will ever need. - */ - nInstr += VM_STACK_GUARD; - pStack = (jx9_value *)SyMemBackendAlloc(&pVm->sAllocator, nInstr * sizeof(jx9_value)); - if( pStack == 0 ){ - return 0; - } - /* Initialize the operand stack */ - while( nInstr > 0 ){ - jx9MemObjInit(&(*pVm), &pStack[nInstr - 1]); - --nInstr; - } - /* Ready for bytecode execution */ - return pStack; -} -/* Forward declaration */ -static sxi32 VmRegisterSpecialFunction(jx9_vm *pVm); -/* - * Prepare the Virtual Machine for bytecode execution. - * This routine gets called by the JX9 engine after - * successful compilation of the target JX9 program. - */ -JX9_PRIVATE sxi32 jx9VmMakeReady( - jx9_vm *pVm /* Target VM */ - ) -{ - sxi32 rc; - if( pVm->nMagic != JX9_VM_INIT ){ - /* Initialize your VM first */ - return SXERR_CORRUPT; - } - /* Mark the VM ready for bytecode execution */ - pVm->nMagic = JX9_VM_RUN; - /* Release the code generator now we have compiled our program */ - jx9ResetCodeGenerator(pVm, 0, 0); - /* Emit the DONE instruction */ - rc = jx9VmEmitInstr(&(*pVm), JX9_OP_DONE, 0, 0, 0, 0); - if( rc != SXRET_OK ){ - return SXERR_MEM; - } - /* Script return value */ - jx9MemObjInit(&(*pVm), &pVm->sExec); /* Assume a NULL return value */ - /* Allocate a new operand stack */ - pVm->aOps = VmNewOperandStack(&(*pVm), SySetUsed(pVm->pByteContainer)); - if( pVm->aOps == 0 ){ - return SXERR_MEM; - } - /* Set the default VM output consumer callback and it's - * private data. */ - pVm->sVmConsumer.xConsumer = jx9VmBlobConsumer; - pVm->sVmConsumer.pUserData = &pVm->sConsumer; - /* Register special functions first [i.e: print, func_get_args(), die, etc.] */ - rc = VmRegisterSpecialFunction(&(*pVm)); - if( rc != SXRET_OK ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return rc; - } - /* Create superglobals [i.e: $GLOBALS, $_GET, $_POST...] */ - rc = jx9HashmapLoadBuiltin(&(*pVm)); - if( rc != SXRET_OK ){ - /* Don't worry about freeing memory, everything will be released shortly */ - return rc; - } - /* Register built-in constants [i.e: JX9_EOL, JX9_OS...] */ - jx9RegisterBuiltInConstant(&(*pVm)); - /* Register built-in functions [i.e: is_null(), array_diff(), strlen(), etc.] */ - jx9RegisterBuiltInFunction(&(*pVm)); - /* VM is ready for bytecode execution */ - return SXRET_OK; -} -/* - * Reset a Virtual Machine to it's initial state. - */ -JX9_PRIVATE sxi32 jx9VmReset(jx9_vm *pVm) -{ - if( pVm->nMagic != JX9_VM_RUN && pVm->nMagic != JX9_VM_EXEC ){ - return SXERR_CORRUPT; - } - /* TICKET 1433-003: As of this version, the VM is automatically reset */ - SyBlobReset(&pVm->sConsumer); - jx9MemObjRelease(&pVm->sExec); - /* Set the ready flag */ - pVm->nMagic = JX9_VM_RUN; - return SXRET_OK; -} -/* - * Release a Virtual Machine. - * Every virtual machine must be destroyed in order to avoid memory leaks. - */ -JX9_PRIVATE sxi32 jx9VmRelease(jx9_vm *pVm) -{ - /* Set the stale magic number */ - pVm->nMagic = JX9_VM_STALE; - /* Release the private memory subsystem */ - SyMemBackendRelease(&pVm->sAllocator); - return SXRET_OK; -} -/* - * Initialize a foreign function call context. - * The context in which a foreign function executes is stored in a jx9_context object. - * A pointer to a jx9_context object is always first parameter to application-defined foreign - * functions. - * The application-defined foreign function implementation will pass this pointer through into - * calls to dozens of interfaces, these includes jx9_result_int(), jx9_result_string(), jx9_result_value(), - * jx9_context_new_scalar(), jx9_context_alloc_chunk(), jx9_context_output(), jx9_context_throw_error() - * and many more. Refer to the C/C++ Interfaces documentation for additional information. - */ -static sxi32 VmInitCallContext( - jx9_context *pOut, /* Call Context */ - jx9_vm *pVm, /* Target VM */ - jx9_user_func *pFunc, /* Foreign function to execute shortly */ - jx9_value *pRet, /* Store return value here*/ - sxi32 iFlags /* Control flags */ - ) -{ - pOut->pFunc = pFunc; - pOut->pVm = pVm; - SySetInit(&pOut->sVar, &pVm->sAllocator, sizeof(jx9_value *)); - SySetInit(&pOut->sChunk, &pVm->sAllocator, sizeof(jx9_aux_data)); - /* Assume a null return value */ - MemObjSetType(pRet, MEMOBJ_NULL); - pOut->pRet = pRet; - pOut->iFlags = iFlags; - return SXRET_OK; -} -/* - * Release a foreign function call context and cleanup the mess - * left behind. - */ -static void VmReleaseCallContext(jx9_context *pCtx) -{ - sxu32 n; - if( SySetUsed(&pCtx->sVar) > 0 ){ - jx9_value **apObj = (jx9_value **)SySetBasePtr(&pCtx->sVar); - for( n = 0 ; n < SySetUsed(&pCtx->sVar) ; ++n ){ - if( apObj[n] == 0 ){ - /* Already released */ - continue; - } - jx9MemObjRelease(apObj[n]); - SyMemBackendPoolFree(&pCtx->pVm->sAllocator, apObj[n]); - } - SySetRelease(&pCtx->sVar); - } - if( SySetUsed(&pCtx->sChunk) > 0 ){ - jx9_aux_data *aAux; - void *pChunk; - /* Automatic release of dynamically allocated chunk - * using [jx9_context_alloc_chunk()]. - */ - aAux = (jx9_aux_data *)SySetBasePtr(&pCtx->sChunk); - for( n = 0; n < SySetUsed(&pCtx->sChunk) ; ++n ){ - pChunk = aAux[n].pAuxData; - /* Release the chunk */ - if( pChunk ){ - SyMemBackendFree(&pCtx->pVm->sAllocator, pChunk); - } - } - SySetRelease(&pCtx->sChunk); - } -} -/* - * Release a jx9_value allocated from the body of a foreign function. - * Refer to [jx9_context_release_value()] for additional information. - */ -JX9_PRIVATE void jx9VmReleaseContextValue( - jx9_context *pCtx, /* Call context */ - jx9_value *pValue /* Release this value */ - ) -{ - if( pValue == 0 ){ - /* NULL value is a harmless operation */ - return; - } - if( SySetUsed(&pCtx->sVar) > 0 ){ - jx9_value **apObj = (jx9_value **)SySetBasePtr(&pCtx->sVar); - sxu32 n; - for( n = 0 ; n < SySetUsed(&pCtx->sVar) ; ++n ){ - if( apObj[n] == pValue ){ - jx9MemObjRelease(pValue); - SyMemBackendPoolFree(&pCtx->pVm->sAllocator, pValue); - /* Mark as released */ - apObj[n] = 0; - break; - } - } - } -} -/* - * Pop and release as many memory object from the operand stack. - */ -static void VmPopOperand( - jx9_value **ppTos, /* Operand stack */ - sxi32 nPop /* Total number of memory objects to pop */ - ) -{ - jx9_value *pTos = *ppTos; - while( nPop > 0 ){ - jx9MemObjRelease(pTos); - pTos--; - nPop--; - } - /* Top of the stack */ - *ppTos = pTos; -} -/* - * Reserve a memory object. - * Return a pointer to the raw jx9_value on success. NULL on failure. - */ -JX9_PRIVATE jx9_value * jx9VmReserveMemObj(jx9_vm *pVm,sxu32 *pIdx) -{ - jx9_value *pObj = 0; - VmSlot *pSlot; - sxu32 nIdx; - /* Check for a free slot */ - nIdx = SXU32_HIGH; /* cc warning */ - pSlot = (VmSlot *)SySetPop(&pVm->aFreeObj); - if( pSlot ){ - pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pSlot->nIdx); - nIdx = pSlot->nIdx; - } - if( pObj == 0 ){ - /* Reserve a new memory object */ - pObj = VmReserveMemObj(&(*pVm), &nIdx); - if( pObj == 0 ){ - return 0; - } - } - /* Set a null default value */ - jx9MemObjInit(&(*pVm), pObj); - if( pIdx ){ - *pIdx = nIdx; - } - pObj->nIdx = nIdx; - return pObj; -} -/* - * Extract a variable value from the top active VM frame. - * Return a pointer to the variable value on success. - * NULL otherwise (non-existent variable/Out-of-memory, ...). - */ -static jx9_value * VmExtractMemObj( - jx9_vm *pVm, /* Target VM */ - const SyString *pName, /* Variable name */ - int bDup, /* True to duplicate variable name */ - int bCreate /* True to create the variable if non-existent */ - ) -{ - int bNullify = FALSE; - SyHashEntry *pEntry; - VmFrame *pFrame; - jx9_value *pObj; - sxu32 nIdx; - sxi32 rc; - /* Point to the top active frame */ - pFrame = pVm->pFrame; - /* Perform the lookup */ - if( pName == 0 || pName->nByte < 1 ){ - static const SyString sAnnon = { " " , sizeof(char) }; - pName = &sAnnon; - /* Always nullify the object */ - bNullify = TRUE; - bDup = FALSE; - } - /* Check the superglobals table first */ - pEntry = SyHashGet(&pVm->hSuper, (const void *)pName->zString, pName->nByte); - if( pEntry == 0 ){ - /* Query the top active frame */ - pEntry = SyHashGet(&pFrame->hVar, (const void *)pName->zString, pName->nByte); - if( pEntry == 0 ){ - char *zName = (char *)pName->zString; - VmSlot sLocal; - if( !bCreate ){ - /* Do not create the variable, return NULL */ - return 0; - } - /* No such variable, automatically create a new one and install - * it in the current frame. - */ - pObj = jx9VmReserveMemObj(&(*pVm),&nIdx); - if( pObj == 0 ){ - return 0; - } - if( bDup ){ - /* Duplicate name */ - zName = SyMemBackendStrDup(&pVm->sAllocator, pName->zString, pName->nByte); - if( zName == 0 ){ - return 0; - } - } - /* Link to the top active VM frame */ - rc = SyHashInsert(&pFrame->hVar, zName, pName->nByte, SX_INT_TO_PTR(nIdx)); - if( rc != SXRET_OK ){ - /* Return the slot to the free pool */ - sLocal.nIdx = nIdx; - sLocal.pUserData = 0; - SySetPut(&pVm->aFreeObj, (const void *)&sLocal); - return 0; - } - if( pFrame->pParent != 0 ){ - /* Local variable */ - sLocal.nIdx = nIdx; - SySetPut(&pFrame->sLocal, (const void *)&sLocal); - } - }else{ - /* Extract variable contents */ - nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); - pObj = (jx9_value *)SySetAt(&pVm->aMemObj, nIdx); - if( bNullify && pObj ){ - jx9MemObjRelease(pObj); - } - } - }else{ - /* Superglobal */ - nIdx = (sxu32)SX_PTR_TO_INT(pEntry->pUserData); - pObj = (jx9_value *)SySetAt(&pVm->aMemObj, nIdx); - } - return pObj; -} -/* - * Extract a superglobal variable such as $_GET, $_POST, $_HEADERS, .... - * Return a pointer to the variable value on success.NULL otherwise. - */ -static jx9_value * VmExtractSuper( - jx9_vm *pVm, /* Target VM */ - const char *zName, /* Superglobal name: NOT NULL TERMINATED */ - sxu32 nByte /* zName length */ - ) -{ - SyHashEntry *pEntry; - jx9_value *pValue; - sxu32 nIdx; - /* Query the superglobal table */ - pEntry = SyHashGet(&pVm->hSuper, (const void *)zName, nByte); - if( pEntry == 0 ){ - /* No such entry */ - return 0; - } - /* Extract the superglobal index in the global object pool */ - nIdx = SX_PTR_TO_INT(pEntry->pUserData); - /* Extract the variable value */ - pValue = (jx9_value *)SySetAt(&pVm->aMemObj, nIdx); - return pValue; -} -/* - * Perform a raw hashmap insertion. - * Refer to the [jx9VmConfigure()] implementation for additional information. - */ -static sxi32 VmHashmapInsert( - jx9_hashmap *pMap, /* Target hashmap */ - const char *zKey, /* Entry key */ - int nKeylen, /* zKey length*/ - const char *zData, /* Entry data */ - int nLen /* zData length */ - ) -{ - jx9_value sKey,sValue; - jx9_value *pKey; - sxi32 rc; - pKey = 0; - jx9MemObjInit(pMap->pVm, &sKey); - jx9MemObjInitFromString(pMap->pVm, &sValue, 0); - if( zKey ){ - if( nKeylen < 0 ){ - nKeylen = (int)SyStrlen(zKey); - } - jx9MemObjStringAppend(&sKey, zKey, (sxu32)nKeylen); - pKey = &sKey; - } - if( zData ){ - if( nLen < 0 ){ - /* Compute length automatically */ - nLen = (int)SyStrlen(zData); - } - jx9MemObjStringAppend(&sValue, zData, (sxu32)nLen); - } - /* Perform the insertion */ - rc = jx9HashmapInsert(&(*pMap),pKey,&sValue); - jx9MemObjRelease(&sKey); - jx9MemObjRelease(&sValue); - return rc; -} -/* Forward declaration */ -static sxi32 VmHttpProcessRequest(jx9_vm *pVm, const char *zRequest, int nByte); -/* - * Configure a working virtual machine instance. - * - * This routine is used to configure a JX9 virtual machine obtained by a prior - * successful call to one of the compile interface such as jx9_compile() - * jx9_compile_v2() or jx9_compile_file(). - * The second argument to this function is an integer configuration option - * that determines what property of the JX9 virtual machine is to be configured. - * Subsequent arguments vary depending on the configuration option in the second - * argument. There are many verbs but the most important are JX9_VM_CONFIG_OUTPUT, - * JX9_VM_CONFIG_HTTP_REQUEST and JX9_VM_CONFIG_ARGV_ENTRY. - * Refer to the official documentation for the list of allowed verbs. - */ -JX9_PRIVATE sxi32 jx9VmConfigure( - jx9_vm *pVm, /* Target VM */ - sxi32 nOp, /* Configuration verb */ - va_list ap /* Subsequent option arguments */ - ) -{ - sxi32 rc = SXRET_OK; - switch(nOp){ - case JX9_VM_CONFIG_OUTPUT: { - ProcConsumer xConsumer = va_arg(ap, ProcConsumer); - void *pUserData = va_arg(ap, void *); - /* VM output consumer callback */ -#ifdef UNTRUST - if( xConsumer == 0 ){ - rc = SXERR_CORRUPT; - break; - } -#endif - /* Install the output consumer */ - pVm->sVmConsumer.xConsumer = xConsumer; - pVm->sVmConsumer.pUserData = pUserData; - break; - } - case JX9_VM_CONFIG_IMPORT_PATH: { - /* Import path */ - const char *zPath; - SyString sPath; - zPath = va_arg(ap, const char *); -#if defined(UNTRUST) - if( zPath == 0 ){ - rc = SXERR_EMPTY; - break; - } -#endif - SyStringInitFromBuf(&sPath, zPath, SyStrlen(zPath)); - /* Remove trailing slashes and backslashes */ -#ifdef __WINNT__ - SyStringTrimTrailingChar(&sPath, '\\'); -#endif - SyStringTrimTrailingChar(&sPath, '/'); - /* Remove leading and trailing white spaces */ - SyStringFullTrim(&sPath); - if( sPath.nByte > 0 ){ - /* Store the path in the corresponding conatiner */ - rc = SySetPut(&pVm->aPaths, (const void *)&sPath); - } - break; - } - case JX9_VM_CONFIG_ERR_REPORT: - /* Run-Time Error report */ - pVm->bErrReport = 1; - break; - case JX9_VM_CONFIG_RECURSION_DEPTH:{ - /* Recursion depth */ - int nDepth = va_arg(ap, int); - if( nDepth > 2 && nDepth < 1024 ){ - pVm->nMaxDepth = nDepth; - } - break; - } - case JX9_VM_OUTPUT_LENGTH: { - /* VM output length in bytes */ - sxu32 *pOut = va_arg(ap, sxu32 *); -#ifdef UNTRUST - if( pOut == 0 ){ - rc = SXERR_CORRUPT; - break; - } -#endif - *pOut = pVm->nOutputLen; - break; - } - case JX9_VM_CONFIG_CREATE_VAR: { - /* Create a new superglobal/global variable */ - const char *zName = va_arg(ap, const char *); - jx9_value *pValue = va_arg(ap, jx9_value *); - SyHashEntry *pEntry; - jx9_value *pObj; - sxu32 nByte; - sxu32 nIdx; -#ifdef UNTRUST - if( SX_EMPTY_STR(zName) || pValue == 0 ){ - rc = SXERR_CORRUPT; - break; - } -#endif - nByte = SyStrlen(zName); - /* Check if the superglobal is already installed */ - pEntry = SyHashGet(&pVm->hSuper, (const void *)zName, nByte); - if( pEntry ){ - /* Variable already installed */ - nIdx = SX_PTR_TO_INT(pEntry->pUserData); - /* Extract contents */ - pObj = (jx9_value *)SySetAt(&pVm->aMemObj, nIdx); - if( pObj ){ - /* Overwrite old contents */ - jx9MemObjStore(pValue, pObj); - } - }else{ - /* Install a new variable */ - pObj = jx9VmReserveMemObj(&(*pVm),&nIdx); - if( pObj == 0 ){ - rc = SXERR_MEM; - break; - } - /* Copy value */ - jx9MemObjStore(pValue, pObj); - /* Install the superglobal */ - rc = SyHashInsert(&pVm->hSuper, (const void *)zName, nByte, SX_INT_TO_PTR(nIdx)); - } - break; - } - case JX9_VM_CONFIG_SERVER_ATTR: - case JX9_VM_CONFIG_ENV_ATTR: { - const char *zKey = va_arg(ap, const char *); - const char *zValue = va_arg(ap, const char *); - int nLen = va_arg(ap, int); - jx9_hashmap *pMap; - jx9_value *pValue; - if( nOp == JX9_VM_CONFIG_ENV_ATTR ){ - /* Extract the $_ENV superglobal */ - pValue = VmExtractSuper(&(*pVm), "_ENV", sizeof("_ENV")-1); - }else{ - /* Extract the $_SERVER superglobal */ - pValue = VmExtractSuper(&(*pVm), "_SERVER", sizeof("_SERVER")-1); - } - if( pValue == 0 || (pValue->iFlags & MEMOBJ_HASHMAP) == 0 ){ - /* No such entry */ - rc = SXERR_NOTFOUND; - break; - } - /* Point to the hashmap */ - pMap = (jx9_hashmap *)pValue->x.pOther; - /* Perform the insertion */ - rc = VmHashmapInsert(pMap, zKey, -1, zValue, nLen); - break; - } - case JX9_VM_CONFIG_ARGV_ENTRY:{ - /* Script arguments */ - const char *zValue = va_arg(ap, const char *); - jx9_hashmap *pMap; - jx9_value *pValue; - /* Extract the $argv array */ - pValue = VmExtractSuper(&(*pVm), "argv", sizeof("argv")-1); - if( pValue == 0 || (pValue->iFlags & MEMOBJ_HASHMAP) == 0 ){ - /* No such entry */ - rc = SXERR_NOTFOUND; - break; - } - /* Point to the hashmap */ - pMap = (jx9_hashmap *)pValue->x.pOther; - /* Perform the insertion */ - rc = VmHashmapInsert(pMap, 0, 0, zValue,-1); - if( rc == SXRET_OK && zValue && zValue[0] != 0 ){ - if( pMap->nEntry > 1 ){ - /* Append space separator first */ - SyBlobAppend(&pVm->sArgv, (const void *)" ", sizeof(char)); - } - SyBlobAppend(&pVm->sArgv, (const void *)zValue,SyStrlen(zValue)); - } - break; - } - case JX9_VM_CONFIG_EXEC_VALUE: { - /* Script return value */ - jx9_value **ppValue = va_arg(ap, jx9_value **); -#ifdef UNTRUST - if( ppValue == 0 ){ - rc = SXERR_CORRUPT; - break; - } -#endif - *ppValue = &pVm->sExec; - break; - } - case JX9_VM_CONFIG_IO_STREAM: { - /* Register an IO stream device */ - const jx9_io_stream *pStream = va_arg(ap, const jx9_io_stream *); - /* Make sure we are dealing with a valid IO stream */ - if( pStream == 0 || pStream->zName == 0 || pStream->zName[0] == 0 || - pStream->xOpen == 0 || pStream->xRead == 0 ){ - /* Invalid stream */ - rc = SXERR_INVALID; - break; - } - if( pVm->pDefStream == 0 && SyStrnicmp(pStream->zName, "file", sizeof("file")-1) == 0 ){ - /* Make the 'file://' stream the defaut stream device */ - pVm->pDefStream = pStream; - } - /* Insert in the appropriate container */ - rc = SySetPut(&pVm->aIOstream, (const void *)&pStream); - break; - } - case JX9_VM_CONFIG_EXTRACT_OUTPUT: { - /* Point to the VM internal output consumer buffer */ - const void **ppOut = va_arg(ap, const void **); - unsigned int *pLen = va_arg(ap, unsigned int *); -#ifdef UNTRUST - if( ppOut == 0 || pLen == 0 ){ - rc = SXERR_CORRUPT; - break; - } -#endif - *ppOut = SyBlobData(&pVm->sConsumer); - *pLen = SyBlobLength(&pVm->sConsumer); - break; - } - case JX9_VM_CONFIG_HTTP_REQUEST:{ - /* Raw HTTP request*/ - const char *zRequest = va_arg(ap, const char *); - int nByte = va_arg(ap, int); - if( SX_EMPTY_STR(zRequest) ){ - rc = SXERR_EMPTY; - break; - } - if( nByte < 0 ){ - /* Compute length automatically */ - nByte = (int)SyStrlen(zRequest); - } - /* Process the request */ - rc = VmHttpProcessRequest(&(*pVm), zRequest, nByte); - break; - } - default: - /* Unknown configuration option */ - rc = SXERR_UNKNOWN; - break; - } - return rc; -} -/* Forward declaration */ -static const char * VmInstrToString(sxi32 nOp); -/* - * This routine is used to dump JX9 bytecode instructions to a human readable - * format. - * The dump is redirected to the given consumer callback which is responsible - * of consuming the generated dump perhaps redirecting it to its standard output - * (STDOUT). - */ -static sxi32 VmByteCodeDump( - SySet *pByteCode, /* Bytecode container */ - ProcConsumer xConsumer, /* Dump consumer callback */ - void *pUserData /* Last argument to xConsumer() */ - ) -{ - static const char zDump[] = { - "====================================================\n" - "JX9 VM Dump Copyright (C) 2012-2013 Symisc Systems\n" - " http://jx9.symisc.net/\n" - "====================================================\n" - }; - VmInstr *pInstr, *pEnd; - sxi32 rc = SXRET_OK; - sxu32 n; - /* Point to the JX9 instructions */ - pInstr = (VmInstr *)SySetBasePtr(pByteCode); - pEnd = &pInstr[SySetUsed(pByteCode)]; - n = 0; - xConsumer((const void *)zDump, sizeof(zDump)-1, pUserData); - /* Dump instructions */ - for(;;){ - if( pInstr >= pEnd ){ - /* No more instructions */ - break; - } - /* Format and call the consumer callback */ - rc = SyProcFormat(xConsumer, pUserData, "%s %8d %8u %#8x [%u]\n", - VmInstrToString(pInstr->iOp), pInstr->iP1, pInstr->iP2, - SX_PTR_TO_INT(pInstr->p3), n); - if( rc != SXRET_OK ){ - /* Consumer routine request an operation abort */ - return rc; - } - ++n; - pInstr++; /* Next instruction in the stream */ - } - return rc; -} -/* - * Consume a generated run-time error message by invoking the VM output - * consumer callback. - */ -static sxi32 VmCallErrorHandler(jx9_vm *pVm, SyBlob *pMsg) -{ - jx9_output_consumer *pCons = &pVm->sVmConsumer; - sxi32 rc = SXRET_OK; - /* Append a new line */ -#ifdef __WINNT__ - SyBlobAppend(pMsg, "\r\n", sizeof("\r\n")-1); -#else - SyBlobAppend(pMsg, "\n", sizeof(char)); -#endif - /* Invoke the output consumer callback */ - rc = pCons->xConsumer(SyBlobData(pMsg), SyBlobLength(pMsg), pCons->pUserData); - /* Increment output length */ - pVm->nOutputLen += SyBlobLength(pMsg); - - return rc; -} -/* - * Throw a run-time error and invoke the supplied VM output consumer callback. - * Refer to the implementation of [jx9_context_throw_error()] for additional - * information. - */ -JX9_PRIVATE sxi32 jx9VmThrowError( - jx9_vm *pVm, /* Target VM */ - SyString *pFuncName, /* Function name. NULL otherwise */ - sxi32 iErr, /* Severity level: [i.e: Error, Warning or Notice]*/ - const char *zMessage /* Null terminated error message */ - ) -{ - SyBlob *pWorker = &pVm->sWorker; - SyString *pFile; - char *zErr; - sxi32 rc; - if( !pVm->bErrReport ){ - /* Don't bother reporting errors */ - return SXRET_OK; - } - /* Reset the working buffer */ - SyBlobReset(pWorker); - /* Peek the processed file if available */ - pFile = (SyString *)SySetPeek(&pVm->aFiles); - if( pFile ){ - /* Append file name */ - SyBlobAppend(pWorker, pFile->zString, pFile->nByte); - SyBlobAppend(pWorker, (const void *)" ", sizeof(char)); - } - zErr = "Error: "; - switch(iErr){ - case JX9_CTX_WARNING: zErr = "Warning: "; break; - case JX9_CTX_NOTICE: zErr = "Notice: "; break; - default: - iErr = JX9_CTX_ERR; - break; - } - SyBlobAppend(pWorker, zErr, SyStrlen(zErr)); - if( pFuncName ){ - /* Append function name first */ - SyBlobAppend(pWorker, pFuncName->zString, pFuncName->nByte); - SyBlobAppend(pWorker, "(): ", sizeof("(): ")-1); - } - SyBlobAppend(pWorker, zMessage, SyStrlen(zMessage)); - /* Consume the error message */ - rc = VmCallErrorHandler(&(*pVm), pWorker); - return rc; -} -/* - * Format and throw a run-time error and invoke the supplied VM output consumer callback. - * Refer to the implementation of [jx9_context_throw_error_format()] for additional - * information. - */ -static sxi32 VmThrowErrorAp( - jx9_vm *pVm, /* Target VM */ - SyString *pFuncName, /* Function name. NULL otherwise */ - sxi32 iErr, /* Severity level: [i.e: Error, Warning or Notice] */ - const char *zFormat, /* Format message */ - va_list ap /* Variable list of arguments */ - ) -{ - SyBlob *pWorker = &pVm->sWorker; - SyString *pFile; - char *zErr; - sxi32 rc; - if( !pVm->bErrReport ){ - /* Don't bother reporting errors */ - return SXRET_OK; - } - /* Reset the working buffer */ - SyBlobReset(pWorker); - /* Peek the processed file if available */ - pFile = (SyString *)SySetPeek(&pVm->aFiles); - if( pFile ){ - /* Append file name */ - SyBlobAppend(pWorker, pFile->zString, pFile->nByte); - SyBlobAppend(pWorker, (const void *)" ", sizeof(char)); - } - zErr = "Error: "; - switch(iErr){ - case JX9_CTX_WARNING: zErr = "Warning: "; break; - case JX9_CTX_NOTICE: zErr = "Notice: "; break; - default: - iErr = JX9_CTX_ERR; - break; - } - SyBlobAppend(pWorker, zErr, SyStrlen(zErr)); - if( pFuncName ){ - /* Append function name first */ - SyBlobAppend(pWorker, pFuncName->zString, pFuncName->nByte); - SyBlobAppend(pWorker, "(): ", sizeof("(): ")-1); - } - SyBlobFormatAp(pWorker, zFormat, ap); - /* Consume the error message */ - rc = VmCallErrorHandler(&(*pVm), pWorker); - return rc; -} -/* - * Format and throw a run-time error and invoke the supplied VM output consumer callback. - * Refer to the implementation of [jx9_context_throw_error_format()] for additional - * information. - * ------------------------------------ - * Simple boring wrapper function. - * ------------------------------------ - */ -static sxi32 VmErrorFormat(jx9_vm *pVm, sxi32 iErr, const char *zFormat, ...) -{ - va_list ap; - sxi32 rc; - va_start(ap, zFormat); - rc = VmThrowErrorAp(&(*pVm), 0, iErr, zFormat, ap); - va_end(ap); - return rc; -} -/* - * Format and throw a run-time error and invoke the supplied VM output consumer callback. - * Refer to the implementation of [jx9_context_throw_error_format()] for additional - * information. - * ------------------------------------ - * Simple boring wrapper function. - * ------------------------------------ - */ -JX9_PRIVATE sxi32 jx9VmThrowErrorAp(jx9_vm *pVm, SyString *pFuncName, sxi32 iErr, const char *zFormat, va_list ap) -{ - sxi32 rc; - rc = VmThrowErrorAp(&(*pVm), &(*pFuncName), iErr, zFormat, ap); - return rc; -} -/* Forward declaration */ -static sxi32 VmLocalExec(jx9_vm *pVm,SySet *pByteCode,jx9_value *pResult); -/* - * Execute as much of a JX9 bytecode program as we can then return. - * - * [jx9VmMakeReady()] must be called before this routine in order to - * close the program with a final OP_DONE and to set up the default - * consumer routines and other stuff. Refer to the implementation - * of [jx9VmMakeReady()] for additional information. - * If the installed VM output consumer callback ever returns JX9_ABORT - * then the program execution is halted. - * After this routine has finished, [jx9VmRelease()] or [jx9VmReset()] - * should be used respectively to clean up the mess that was left behind - * or to reset the VM to it's initial state. - */ -static sxi32 VmByteCodeExec( - jx9_vm *pVm, /* Target VM */ - VmInstr *aInstr, /* JX9 bytecode program */ - jx9_value *pStack, /* Operand stack */ - int nTos, /* Top entry in the operand stack (usually -1) */ - jx9_value *pResult /* Store program return value here. NULL otherwise */ - ) -{ - VmInstr *pInstr; - jx9_value *pTos; - SySet aArg; - sxi32 pc; - sxi32 rc; - /* Argument container */ - SySetInit(&aArg, &pVm->sAllocator, sizeof(jx9_value *)); - if( nTos < 0 ){ - pTos = &pStack[-1]; - }else{ - pTos = &pStack[nTos]; - } - pc = 0; - /* Execute as much as we can */ - for(;;){ - /* Fetch the instruction to execute */ - pInstr = &aInstr[pc]; - rc = SXRET_OK; -/* - * What follows here is a massive switch statement where each case implements a - * separate instruction in the virtual machine. If we follow the usual - * indentation convention each case should be indented by 6 spaces. But - * that is a lot of wasted space on the left margin. So the code within - * the switch statement will break with convention and be flush-left. - */ - switch(pInstr->iOp){ -/* - * DONE: P1 * * - * - * Program execution completed: Clean up the mess left behind - * and return immediately. - */ -case JX9_OP_DONE: - if( pInstr->iP1 ){ -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( pResult ){ - /* Execution result */ - jx9MemObjStore(pTos, pResult); - } - VmPopOperand(&pTos, 1); - } - goto Done; -/* - * HALT: P1 * * - * - * Program execution aborted: Clean up the mess left behind - * and abort immediately. - */ -case JX9_OP_HALT: - if( pInstr->iP1 ){ -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( pTos->iFlags & MEMOBJ_STRING ){ - if( SyBlobLength(&pTos->sBlob) > 0 ){ - /* Output the exit message */ - pVm->sVmConsumer.xConsumer(SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob), - pVm->sVmConsumer.pUserData); - /* Increment output length */ - pVm->nOutputLen += SyBlobLength(&pTos->sBlob); - } - }else if(pTos->iFlags & MEMOBJ_INT ){ - /* Record exit status */ - pVm->iExitStatus = (sxi32)pTos->x.iVal; - } - VmPopOperand(&pTos, 1); - } - goto Abort; -/* - * JMP: * P2 * - * - * Unconditional jump: The next instruction executed will be - * the one at index P2 from the beginning of the program. - */ -case JX9_OP_JMP: - pc = pInstr->iP2 - 1; - break; -/* - * JZ: P1 P2 * - * - * Take the jump if the top value is zero (FALSE jump).Pop the top most - * entry in the stack if P1 is zero. - */ -case JX9_OP_JZ: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Get a boolean value */ - if((pTos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pTos); - } - if( !pTos->x.iVal ){ - /* Take the jump */ - pc = pInstr->iP2 - 1; - } - if( !pInstr->iP1 ){ - VmPopOperand(&pTos, 1); - } - break; -/* - * JNZ: P1 P2 * - * - * Take the jump if the top value is not zero (TRUE jump).Pop the top most - * entry in the stack if P1 is zero. - */ -case JX9_OP_JNZ: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Get a boolean value */ - if((pTos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pTos); - } - if( pTos->x.iVal ){ - /* Take the jump */ - pc = pInstr->iP2 - 1; - } - if( !pInstr->iP1 ){ - VmPopOperand(&pTos, 1); - } - break; -/* - * NOOP: * * * - * - * Do nothing. This instruction is often useful as a jump - * destination. - */ -case JX9_OP_NOOP: - break; -/* - * POP: P1 * * - * - * Pop P1 elements from the operand stack. - */ -case JX9_OP_POP: { - sxi32 n = pInstr->iP1; - if( &pTos[-n+1] < pStack ){ - /* TICKET 1433-51 Stack underflow must be handled at run-time */ - n = (sxi32)(pTos - pStack); - } - VmPopOperand(&pTos, n); - break; - } -/* - * CVT_INT: * * * - * - * Force the top of the stack to be an integer. - */ -case JX9_OP_CVT_INT: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if((pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_INT); - break; -/* - * CVT_REAL: * * * - * - * Force the top of the stack to be a real. - */ -case JX9_OP_CVT_REAL: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if((pTos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pTos); - } - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_REAL); - break; -/* - * CVT_STR: * * * - * - * Force the top of the stack to be a string. - */ -case JX9_OP_CVT_STR: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( (pTos->iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(pTos); - } - break; -/* - * CVT_BOOL: * * * - * - * Force the top of the stack to be a boolean. - */ -case JX9_OP_CVT_BOOL: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( (pTos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pTos); - } - break; -/* - * CVT_NULL: * * * - * - * Nullify the top of the stack. - */ -case JX9_OP_CVT_NULL: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - jx9MemObjRelease(pTos); - break; -/* - * CVT_NUMC: * * * - * - * Force the top of the stack to be a numeric type (integer, real or both). - */ -case JX9_OP_CVT_NUMC: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Force a numeric cast */ - jx9MemObjToNumeric(pTos); - break; -/* - * CVT_ARRAY: * * * - * - * Force the top of the stack to be a hashmap aka 'array'. - */ -case JX9_OP_CVT_ARRAY: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Force a hashmap cast */ - rc = jx9MemObjToHashmap(pTos); - if( rc != SXRET_OK ){ - /* Not so fatal, emit a simple warning */ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_WARNING, - "JX9 engine is running out of memory while performing an array cast"); - } - break; -/* - * LOADC P1 P2 * - * - * Load a constant [i.e: JX9_EOL, JX9_OS, __TIME__, ...] indexed at P2 in the constant pool. - * If P1 is set, then this constant is candidate for expansion via user installable callbacks. - */ -case JX9_OP_LOADC: { - jx9_value *pObj; - /* Reserve a room */ - pTos++; - if( (pObj = (jx9_value *)SySetAt(&pVm->aLitObj, pInstr->iP2)) != 0 ){ - if( pInstr->iP1 == 1 && SyBlobLength(&pObj->sBlob) <= 64 ){ - SyHashEntry *pEntry; - /* Candidate for expansion via user defined callbacks */ - pEntry = SyHashGet(&pVm->hConstant, SyBlobData(&pObj->sBlob), SyBlobLength(&pObj->sBlob)); - if( pEntry ){ - jx9_constant *pCons = (jx9_constant *)pEntry->pUserData; - /* Set a NULL default value */ - MemObjSetType(pTos, MEMOBJ_NULL); - SyBlobReset(&pTos->sBlob); - /* Invoke the callback and deal with the expanded value */ - pCons->xExpand(pTos, pCons->pUserData); - /* Mark as constant */ - pTos->nIdx = SXU32_HIGH; - break; - } - } - jx9MemObjLoad(pObj, pTos); - }else{ - /* Set a NULL value */ - MemObjSetType(pTos, MEMOBJ_NULL); - } - /* Mark as constant */ - pTos->nIdx = SXU32_HIGH; - break; - } -/* - * LOAD: P1 * P3 - * - * Load a variable where it's name is taken from the top of the stack or - * from the P3 operand. - * If P1 is set, then perform a lookup only.In other words do not create - * the variable if non existent and push the NULL constant instead. - */ -case JX9_OP_LOAD:{ - jx9_value *pObj; - SyString sName; - if( pInstr->p3 == 0 ){ - /* Take the variable name from the top of the stack */ -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Force a string cast */ - if( (pTos->iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(pTos); - } - SyStringInitFromBuf(&sName, SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); - }else{ - SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3)); - /* Reserve a room for the target object */ - pTos++; - } - /* Extract the requested memory object */ - pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, pInstr->iP1 != 1); - if( pObj == 0 ){ - if( pInstr->iP1 ){ - /* Variable not found, load NULL */ - if( !pInstr->p3 ){ - jx9MemObjRelease(pTos); - }else{ - MemObjSetType(pTos, MEMOBJ_NULL); - } - pTos->nIdx = SXU32_HIGH; /* Mark as constant */ - break; - }else{ - /* Fatal error */ - VmErrorFormat(&(*pVm), JX9_CTX_ERR, "Fatal, JX9 engine is running out of memory while loading variable '%z'", &sName); - goto Abort; - } - } - /* Load variable contents */ - jx9MemObjLoad(pObj, pTos); - pTos->nIdx = pObj->nIdx; - break; - } -/* - * LOAD_MAP P1 * * - * - * Allocate a new empty hashmap (array in the JX9 jargon) and push it on the stack. - * If the P1 operand is greater than zero then pop P1 elements from the - * stack and insert them (key => value pair) in the new hashmap. - */ -case JX9_OP_LOAD_MAP: { - jx9_hashmap *pMap; - int is_json_object; /* TRUE if we are dealing with a JSON object */ - int iIncr = 1; - /* Allocate a new hashmap instance */ - pMap = jx9NewHashmap(&(*pVm), 0, 0); - if( pMap == 0 ){ - VmErrorFormat(&(*pVm), JX9_CTX_ERR, - "Fatal, JX9 engine is running out of memory while loading JSON array/object at instruction #:%d", pc); - goto Abort; - } - is_json_object = 0; - if( pInstr->iP2 ){ - /* JSON object, record that */ - pMap->iFlags |= HASHMAP_JSON_OBJECT; - is_json_object = 1; - iIncr = 2; - } - if( pInstr->iP1 > 0 ){ - jx9_value *pEntry = &pTos[-pInstr->iP1+1]; /* Point to the first entry */ - /* Perform the insertion */ - while( pEntry <= pTos ){ - /* Standard insertion */ - jx9HashmapInsert(pMap, - is_json_object ? pEntry : 0 /* Automatic index assign */, - is_json_object ? &pEntry[1] : pEntry - ); - /* Next pair on the stack */ - pEntry += iIncr; - } - /* Pop P1 elements */ - VmPopOperand(&pTos, pInstr->iP1); - } - /* Push the hashmap */ - pTos++; - pTos->x.pOther = pMap; - MemObjSetType(pTos, MEMOBJ_HASHMAP); - break; - } -/* - * LOAD_IDX: P1 P2 * - * - * Load a hasmap entry where it's index (either numeric or string) is taken - * from the stack. - * If the index does not refer to a valid element, then push the NULL constant - * instead. - */ -case JX9_OP_LOAD_IDX: { - jx9_hashmap_node *pNode = 0; /* cc warning */ - jx9_hashmap *pMap = 0; - jx9_value *pIdx; - pIdx = 0; - if( pInstr->iP1 == 0 ){ - if( !pInstr->iP2){ - /* No available index, load NULL */ - if( pTos >= pStack ){ - jx9MemObjRelease(pTos); - }else{ - /* TICKET 1433-020: Empty stack */ - pTos++; - MemObjSetType(pTos, MEMOBJ_NULL); - pTos->nIdx = SXU32_HIGH; - } - /* Emit a notice */ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_NOTICE, - "JSON Array/Object: Attempt to access an undefined member, JX9 is loading NULL"); - break; - } - }else{ - pIdx = pTos; - pTos--; - } - if( pTos->iFlags & MEMOBJ_STRING ){ - /* String access */ - if( pIdx ){ - sxu32 nOfft; - if( (pIdx->iFlags & MEMOBJ_INT) == 0 ){ - /* Force an int cast */ - jx9MemObjToInteger(pIdx); - } - nOfft = (sxu32)pIdx->x.iVal; - if( nOfft >= SyBlobLength(&pTos->sBlob) ){ - /* Invalid offset, load null */ - jx9MemObjRelease(pTos); - }else{ - const char *zData = (const char *)SyBlobData(&pTos->sBlob); - int c = zData[nOfft]; - jx9MemObjRelease(pTos); - MemObjSetType(pTos, MEMOBJ_STRING); - SyBlobAppend(&pTos->sBlob, (const void *)&c, sizeof(char)); - } - }else{ - /* No available index, load NULL */ - MemObjSetType(pTos, MEMOBJ_NULL); - } - break; - } - if( pInstr->iP2 && (pTos->iFlags & MEMOBJ_HASHMAP) == 0 ){ - if( pTos->nIdx != SXU32_HIGH ){ - jx9_value *pObj; - if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjToHashmap(pObj); - jx9MemObjLoad(pObj, pTos); - } - } - } - rc = SXERR_NOTFOUND; /* Assume the index is invalid */ - if( pTos->iFlags & MEMOBJ_HASHMAP ){ - /* Point to the hashmap */ - pMap = (jx9_hashmap *)pTos->x.pOther; - if( pIdx ){ - /* Load the desired entry */ - rc = jx9HashmapLookup(pMap, pIdx, &pNode); - } - if( rc != SXRET_OK && pInstr->iP2 ){ - /* Create a new empty entry */ - rc = jx9HashmapInsert(pMap, pIdx, 0); - if( rc == SXRET_OK ){ - /* Point to the last inserted entry */ - pNode = pMap->pLast; - } - } - } - if( pIdx ){ - jx9MemObjRelease(pIdx); - } - if( rc == SXRET_OK ){ - /* Load entry contents */ - if( pMap->iRef < 2 ){ - /* TICKET 1433-42: Array will be deleted shortly, so we will make a copy - * of the entry value, rather than pointing to it. - */ - pTos->nIdx = SXU32_HIGH; - jx9HashmapExtractNodeValue(pNode, pTos, TRUE); - }else{ - pTos->nIdx = pNode->nValIdx; - jx9HashmapExtractNodeValue(pNode, pTos, FALSE); - jx9HashmapUnref(pMap); - } - }else{ - /* No such entry, load NULL */ - jx9MemObjRelease(pTos); - pTos->nIdx = SXU32_HIGH; - } - break; - } -/* - * STORE * P2 P3 - * - * Perform a store (Assignment) operation. - */ -case JX9_OP_STORE: { - jx9_value *pObj; - SyString sName; -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( pInstr->iP2 ){ - sxu32 nIdx; - /* Member store operation */ - nIdx = pTos->nIdx; - VmPopOperand(&pTos, 1); - if( nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, - "Cannot perform assignment on a constant object attribute, JX9 is loading NULL"); - pTos->nIdx = SXU32_HIGH; - }else{ - /* Point to the desired memory object */ - pObj = (jx9_value *)SySetAt(&pVm->aMemObj, nIdx); - if( pObj ){ - /* Perform the store operation */ - jx9MemObjStore(pTos, pObj); - } - } - break; - }else if( pInstr->p3 == 0 ){ - /* Take the variable name from the next on the stack */ - if( (pTos->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(pTos); - } - SyStringInitFromBuf(&sName, SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); - pTos--; -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - }else{ - SyStringInitFromBuf(&sName, pInstr->p3, SyStrlen((const char *)pInstr->p3)); - } - /* Extract the desired variable and if not available dynamically create it */ - pObj = VmExtractMemObj(&(*pVm), &sName, pInstr->p3 ? FALSE : TRUE, TRUE); - if( pObj == 0 ){ - VmErrorFormat(&(*pVm), JX9_CTX_ERR, - "Fatal, JX9 engine is running out of memory while loading variable '%z'", &sName); - goto Abort; - } - if( !pInstr->p3 ){ - jx9MemObjRelease(&pTos[1]); - } - /* Perform the store operation */ - jx9MemObjStore(pTos, pObj); - break; - } -/* - * STORE_IDX: P1 * P3 - * - * Perfrom a store operation an a hashmap entry. - */ -case JX9_OP_STORE_IDX: { - jx9_hashmap *pMap = 0; /* cc warning */ - jx9_value *pKey; - sxu32 nIdx; - if( pInstr->iP1 ){ - /* Key is next on stack */ - pKey = pTos; - pTos--; - }else{ - pKey = 0; - } - nIdx = pTos->nIdx; - if( pTos->iFlags & MEMOBJ_HASHMAP ){ - /* Hashmap already loaded */ - pMap = (jx9_hashmap *)pTos->x.pOther; - if( pMap->iRef < 2 ){ - /* TICKET 1433-48: Prevent garbage collection */ - pMap->iRef = 2; - } - }else{ - jx9_value *pObj; - pObj = (jx9_value *)SySetAt(&pVm->aMemObj, nIdx); - if( pObj == 0 ){ - if( pKey ){ - jx9MemObjRelease(pKey); - } - VmPopOperand(&pTos, 1); - break; - } - /* Phase#1: Load the array */ - if( (pObj->iFlags & MEMOBJ_STRING) ){ - VmPopOperand(&pTos, 1); - if( (pTos->iFlags&MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(pTos); - } - if( pKey == 0 ){ - /* Append string */ - if( SyBlobLength(&pTos->sBlob) > 0 ){ - SyBlobAppend(&pObj->sBlob, SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); - } - }else{ - sxu32 nOfft; - if((pKey->iFlags & MEMOBJ_INT)){ - /* Force an int cast */ - jx9MemObjToInteger(pKey); - } - nOfft = (sxu32)pKey->x.iVal; - if( nOfft < SyBlobLength(&pObj->sBlob) && SyBlobLength(&pTos->sBlob) > 0 ){ - const char *zBlob = (const char *)SyBlobData(&pTos->sBlob); - char *zData = (char *)SyBlobData(&pObj->sBlob); - zData[nOfft] = zBlob[0]; - }else{ - if( SyBlobLength(&pTos->sBlob) >= sizeof(char) ){ - /* Perform an append operation */ - SyBlobAppend(&pObj->sBlob, SyBlobData(&pTos->sBlob), sizeof(char)); - } - } - } - if( pKey ){ - jx9MemObjRelease(pKey); - } - break; - }else if( (pObj->iFlags & MEMOBJ_HASHMAP) == 0 ){ - /* Force a hashmap cast */ - rc = jx9MemObjToHashmap(pObj); - if( rc != SXRET_OK ){ - VmErrorFormat(&(*pVm), JX9_CTX_ERR, "Fatal, JX9 engine is running out of memory while creating a new array"); - goto Abort; - } - } - pMap = (jx9_hashmap *)pObj->x.pOther; - } - VmPopOperand(&pTos, 1); - /* Phase#2: Perform the insertion */ - jx9HashmapInsert(pMap, pKey, pTos); - if( pKey ){ - jx9MemObjRelease(pKey); - } - break; - } -/* - * INCR: P1 * * - * - * Force a numeric cast and increment the top of the stack by 1. - * If the P1 operand is set then perform a duplication of the top of - * the stack and increment after that. - */ -case JX9_OP_INCR: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( (pTos->iFlags & (MEMOBJ_HASHMAP|MEMOBJ_RES)) == 0 ){ - if( pTos->nIdx != SXU32_HIGH ){ - jx9_value *pObj; - if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - /* Force a numeric cast */ - jx9MemObjToNumeric(pObj); - if( pObj->iFlags & MEMOBJ_REAL ){ - pObj->x.rVal++; - /* Try to get an integer representation */ - jx9MemObjTryInteger(pTos); - }else{ - pObj->x.iVal++; - MemObjSetType(pTos, MEMOBJ_INT); - } - if( pInstr->iP1 ){ - /* Pre-icrement */ - jx9MemObjStore(pObj, pTos); - } - } - }else{ - if( pInstr->iP1 ){ - /* Force a numeric cast */ - jx9MemObjToNumeric(pTos); - /* Pre-increment */ - if( pTos->iFlags & MEMOBJ_REAL ){ - pTos->x.rVal++; - /* Try to get an integer representation */ - jx9MemObjTryInteger(pTos); - }else{ - pTos->x.iVal++; - MemObjSetType(pTos, MEMOBJ_INT); - } - } - } - } - break; -/* - * DECR: P1 * * - * - * Force a numeric cast and decrement the top of the stack by 1. - * If the P1 operand is set then perform a duplication of the top of the stack - * and decrement after that. - */ -case JX9_OP_DECR: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( (pTos->iFlags & (MEMOBJ_HASHMAP|MEMOBJ_RES|MEMOBJ_NULL)) == 0 ){ - /* Force a numeric cast */ - jx9MemObjToNumeric(pTos); - if( pTos->nIdx != SXU32_HIGH ){ - jx9_value *pObj; - if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - /* Force a numeric cast */ - jx9MemObjToNumeric(pObj); - if( pObj->iFlags & MEMOBJ_REAL ){ - pObj->x.rVal--; - /* Try to get an integer representation */ - jx9MemObjTryInteger(pTos); - }else{ - pObj->x.iVal--; - MemObjSetType(pTos, MEMOBJ_INT); - } - if( pInstr->iP1 ){ - /* Pre-icrement */ - jx9MemObjStore(pObj, pTos); - } - } - }else{ - if( pInstr->iP1 ){ - /* Pre-increment */ - if( pTos->iFlags & MEMOBJ_REAL ){ - pTos->x.rVal--; - /* Try to get an integer representation */ - jx9MemObjTryInteger(pTos); - }else{ - pTos->x.iVal--; - MemObjSetType(pTos, MEMOBJ_INT); - } - } - } - } - break; -/* - * UMINUS: * * * - * - * Perform a unary minus operation. - */ -case JX9_OP_UMINUS: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Force a numeric (integer, real or both) cast */ - jx9MemObjToNumeric(pTos); - if( pTos->iFlags & MEMOBJ_REAL ){ - pTos->x.rVal = -pTos->x.rVal; - } - if( pTos->iFlags & MEMOBJ_INT ){ - pTos->x.iVal = -pTos->x.iVal; - } - break; -/* - * UPLUS: * * * - * - * Perform a unary plus operation. - */ -case JX9_OP_UPLUS: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Force a numeric (integer, real or both) cast */ - jx9MemObjToNumeric(pTos); - if( pTos->iFlags & MEMOBJ_REAL ){ - pTos->x.rVal = +pTos->x.rVal; - } - if( pTos->iFlags & MEMOBJ_INT ){ - pTos->x.iVal = +pTos->x.iVal; - } - break; -/* - * OP_LNOT: * * * - * - * Interpret the top of the stack as a boolean value. Replace it - * with its complement. - */ -case JX9_OP_LNOT: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Force a boolean cast */ - if( (pTos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pTos); - } - pTos->x.iVal = !pTos->x.iVal; - break; -/* - * OP_BITNOT: * * * - * - * Interpret the top of the stack as an value.Replace it - * with its ones-complement. - */ -case JX9_OP_BITNOT: -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - /* Force an integer cast */ - if( (pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - pTos->x.iVal = ~pTos->x.iVal; - break; -/* OP_MUL * * * - * OP_MUL_STORE * * * - * - * Pop the top two elements from the stack, multiply them together, - * and push the result back onto the stack. - */ -case JX9_OP_MUL: -case JX9_OP_MUL_STORE: { - jx9_value *pNos = &pTos[-1]; - /* Force the operand to be numeric */ -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - jx9MemObjToNumeric(pTos); - jx9MemObjToNumeric(pNos); - /* Perform the requested operation */ - if( MEMOBJ_REAL & (pTos->iFlags|pNos->iFlags) ){ - /* Floating point arithemic */ - jx9_real a, b, r; - if( (pTos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pTos); - } - if( (pNos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pNos); - } - a = pNos->x.rVal; - b = pTos->x.rVal; - r = a * b; - /* Push the result */ - pNos->x.rVal = r; - MemObjSetType(pNos, MEMOBJ_REAL); - /* Try to get an integer representation */ - jx9MemObjTryInteger(pNos); - }else{ - /* Integer arithmetic */ - sxi64 a, b, r; - a = pNos->x.iVal; - b = pTos->x.iVal; - r = a * b; - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - } - if( pInstr->iOp == JX9_OP_MUL_STORE ){ - jx9_value *pObj; - if( pTos->nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjStore(pNos, pObj); - } - } - VmPopOperand(&pTos, 1); - break; - } -/* OP_ADD * * * - * - * Pop the top two elements from the stack, add them together, - * and push the result back onto the stack. - */ -case JX9_OP_ADD:{ - jx9_value *pNos = &pTos[-1]; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Perform the addition */ - jx9MemObjAdd(pNos, pTos, FALSE); - VmPopOperand(&pTos, 1); - break; - } -/* - * OP_ADD_STORE * * * - * - * Pop the top two elements from the stack, add them together, - * and push the result back onto the stack. - */ -case JX9_OP_ADD_STORE:{ - jx9_value *pNos = &pTos[-1]; - jx9_value *pObj; - sxu32 nIdx; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Perform the addition */ - nIdx = pTos->nIdx; - jx9MemObjAdd(pTos, pNos, TRUE); - /* Peform the store operation */ - if( nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, nIdx)) != 0 ){ - jx9MemObjStore(pTos, pObj); - } - /* Ticket 1433-35: Perform a stack dup */ - jx9MemObjStore(pTos, pNos); - VmPopOperand(&pTos, 1); - break; - } -/* OP_SUB * * * - * - * Pop the top two elements from the stack, subtract the - * first (what was next on the stack) from the second (the - * top of the stack) and push the result back onto the stack. - */ -case JX9_OP_SUB: { - jx9_value *pNos = &pTos[-1]; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - if( MEMOBJ_REAL & (pTos->iFlags|pNos->iFlags) ){ - /* Floating point arithemic */ - jx9_real a, b, r; - if( (pTos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pTos); - } - if( (pNos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pNos); - } - a = pNos->x.rVal; - b = pTos->x.rVal; - r = a - b; - /* Push the result */ - pNos->x.rVal = r; - MemObjSetType(pNos, MEMOBJ_REAL); - /* Try to get an integer representation */ - jx9MemObjTryInteger(pNos); - }else{ - /* Integer arithmetic */ - sxi64 a, b, r; - a = pNos->x.iVal; - b = pTos->x.iVal; - r = a - b; - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - } - VmPopOperand(&pTos, 1); - break; - } -/* OP_SUB_STORE * * * - * - * Pop the top two elements from the stack, subtract the - * first (what was next on the stack) from the second (the - * top of the stack) and push the result back onto the stack. - */ -case JX9_OP_SUB_STORE: { - jx9_value *pNos = &pTos[-1]; - jx9_value *pObj; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - if( MEMOBJ_REAL & (pTos->iFlags|pNos->iFlags) ){ - /* Floating point arithemic */ - jx9_real a, b, r; - if( (pTos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pTos); - } - if( (pNos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pNos); - } - a = pTos->x.rVal; - b = pNos->x.rVal; - r = a - b; - /* Push the result */ - pNos->x.rVal = r; - MemObjSetType(pNos, MEMOBJ_REAL); - /* Try to get an integer representation */ - jx9MemObjTryInteger(pNos); - }else{ - /* Integer arithmetic */ - sxi64 a, b, r; - a = pTos->x.iVal; - b = pNos->x.iVal; - r = a - b; - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - } - if( pTos->nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjStore(pNos, pObj); - } - VmPopOperand(&pTos, 1); - break; - } - -/* - * OP_MOD * * * - * - * Pop the top two elements from the stack, divide the - * first (what was next on the stack) from the second (the - * top of the stack) and push the remainder after division - * onto the stack. - * Note: Only integer arithemtic is allowed. - */ -case JX9_OP_MOD:{ - jx9_value *pNos = &pTos[-1]; - sxi64 a, b, r; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be integer */ - if( (pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - if( (pNos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pNos); - } - /* Perform the requested operation */ - a = pNos->x.iVal; - b = pTos->x.iVal; - if( b == 0 ){ - r = 0; - VmErrorFormat(&(*pVm), JX9_CTX_ERR, "Division by zero %qd%%0", a); - /* goto Abort; */ - }else{ - r = a%b; - } - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - VmPopOperand(&pTos, 1); - break; - } -/* - * OP_MOD_STORE * * * - * - * Pop the top two elements from the stack, divide the - * first (what was next on the stack) from the second (the - * top of the stack) and push the remainder after division - * onto the stack. - * Note: Only integer arithemtic is allowed. - */ -case JX9_OP_MOD_STORE: { - jx9_value *pNos = &pTos[-1]; - jx9_value *pObj; - sxi64 a, b, r; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be integer */ - if( (pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - if( (pNos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pNos); - } - /* Perform the requested operation */ - a = pTos->x.iVal; - b = pNos->x.iVal; - if( b == 0 ){ - r = 0; - VmErrorFormat(&(*pVm), JX9_CTX_ERR, "Division by zero %qd%%0", a); - /* goto Abort; */ - }else{ - r = a%b; - } - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - if( pTos->nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjStore(pNos, pObj); - } - VmPopOperand(&pTos, 1); - break; - } -/* - * OP_DIV * * * - * - * Pop the top two elements from the stack, divide the - * first (what was next on the stack) from the second (the - * top of the stack) and push the result onto the stack. - * Note: Only floating point arithemtic is allowed. - */ -case JX9_OP_DIV:{ - jx9_value *pNos = &pTos[-1]; - jx9_real a, b, r; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be real */ - if( (pTos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pTos); - } - if( (pNos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pNos); - } - /* Perform the requested operation */ - a = pNos->x.rVal; - b = pTos->x.rVal; - if( b == 0 ){ - /* Division by zero */ - r = 0; - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Division by zero"); - /* goto Abort; */ - }else{ - r = a/b; - /* Push the result */ - pNos->x.rVal = r; - MemObjSetType(pNos, MEMOBJ_REAL); - /* Try to get an integer representation */ - jx9MemObjTryInteger(pNos); - } - VmPopOperand(&pTos, 1); - break; - } -/* - * OP_DIV_STORE * * * - * - * Pop the top two elements from the stack, divide the - * first (what was next on the stack) from the second (the - * top of the stack) and push the result onto the stack. - * Note: Only floating point arithemtic is allowed. - */ -case JX9_OP_DIV_STORE:{ - jx9_value *pNos = &pTos[-1]; - jx9_value *pObj; - jx9_real a, b, r; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be real */ - if( (pTos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pTos); - } - if( (pNos->iFlags & MEMOBJ_REAL) == 0 ){ - jx9MemObjToReal(pNos); - } - /* Perform the requested operation */ - a = pTos->x.rVal; - b = pNos->x.rVal; - if( b == 0 ){ - /* Division by zero */ - r = 0; - VmErrorFormat(&(*pVm), JX9_CTX_ERR, "Division by zero %qd/0", a); - /* goto Abort; */ - }else{ - r = a/b; - /* Push the result */ - pNos->x.rVal = r; - MemObjSetType(pNos, MEMOBJ_REAL); - /* Try to get an integer representation */ - jx9MemObjTryInteger(pNos); - } - if( pTos->nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjStore(pNos, pObj); - } - VmPopOperand(&pTos, 1); - break; - } -/* OP_BAND * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the bit-wise AND of the - * two elements. -*/ -/* OP_BOR * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the bit-wise OR of the - * two elements. - */ -/* OP_BXOR * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the bit-wise XOR of the - * two elements. - */ -case JX9_OP_BAND: -case JX9_OP_BOR: -case JX9_OP_BXOR:{ - jx9_value *pNos = &pTos[-1]; - sxi64 a, b, r; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be integer */ - if( (pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - if( (pNos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pNos); - } - /* Perform the requested operation */ - a = pNos->x.iVal; - b = pTos->x.iVal; - switch(pInstr->iOp){ - case JX9_OP_BOR_STORE: - case JX9_OP_BOR: r = a|b; break; - case JX9_OP_BXOR_STORE: - case JX9_OP_BXOR: r = a^b; break; - case JX9_OP_BAND_STORE: - case JX9_OP_BAND: - default: r = a&b; break; - } - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - VmPopOperand(&pTos, 1); - break; - } -/* OP_BAND_STORE * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the bit-wise AND of the - * two elements. -*/ -/* OP_BOR_STORE * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the bit-wise OR of the - * two elements. - */ -/* OP_BXOR_STORE * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the bit-wise XOR of the - * two elements. - */ -case JX9_OP_BAND_STORE: -case JX9_OP_BOR_STORE: -case JX9_OP_BXOR_STORE:{ - jx9_value *pNos = &pTos[-1]; - jx9_value *pObj; - sxi64 a, b, r; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be integer */ - if( (pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - if( (pNos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pNos); - } - /* Perform the requested operation */ - a = pTos->x.iVal; - b = pNos->x.iVal; - switch(pInstr->iOp){ - case JX9_OP_BOR_STORE: - case JX9_OP_BOR: r = a|b; break; - case JX9_OP_BXOR_STORE: - case JX9_OP_BXOR: r = a^b; break; - case JX9_OP_BAND_STORE: - case JX9_OP_BAND: - default: r = a&b; break; - } - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - if( pTos->nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjStore(pNos, pObj); - } - VmPopOperand(&pTos, 1); - break; - } -/* OP_SHL * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the second element shifted - * left by N bits where N is the top element on the stack. - * Note: Only integer arithmetic is allowed. - */ -/* OP_SHR * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the second element shifted - * right by N bits where N is the top element on the stack. - * Note: Only integer arithmetic is allowed. - */ -case JX9_OP_SHL: -case JX9_OP_SHR: { - jx9_value *pNos = &pTos[-1]; - sxi64 a, r; - sxi32 b; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be integer */ - if( (pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - if( (pNos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pNos); - } - /* Perform the requested operation */ - a = pNos->x.iVal; - b = (sxi32)pTos->x.iVal; - if( pInstr->iOp == JX9_OP_SHL ){ - r = a << b; - }else{ - r = a >> b; - } - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - VmPopOperand(&pTos, 1); - break; - } -/* OP_SHL_STORE * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the second element shifted - * left by N bits where N is the top element on the stack. - * Note: Only integer arithmetic is allowed. - */ -/* OP_SHR_STORE * * * - * - * Pop the top two elements from the stack. Convert both elements - * to integers. Push back onto the stack the second element shifted - * right by N bits where N is the top element on the stack. - * Note: Only integer arithmetic is allowed. - */ -case JX9_OP_SHL_STORE: -case JX9_OP_SHR_STORE: { - jx9_value *pNos = &pTos[-1]; - jx9_value *pObj; - sxi64 a, r; - sxi32 b; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force the operands to be integer */ - if( (pTos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pTos); - } - if( (pNos->iFlags & MEMOBJ_INT) == 0 ){ - jx9MemObjToInteger(pNos); - } - /* Perform the requested operation */ - a = pTos->x.iVal; - b = (sxi32)pNos->x.iVal; - if( pInstr->iOp == JX9_OP_SHL_STORE ){ - r = a << b; - }else{ - r = a >> b; - } - /* Push the result */ - pNos->x.iVal = r; - MemObjSetType(pNos, MEMOBJ_INT); - if( pTos->nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjStore(pNos, pObj); - } - VmPopOperand(&pTos, 1); - break; - } -/* CAT: P1 * * - * - * Pop P1 elements from the stack. Concatenate them togeher and push the result - * back. - */ -case JX9_OP_CAT:{ - jx9_value *pNos, *pCur; - if( pInstr->iP1 < 1 ){ - pNos = &pTos[-1]; - }else{ - pNos = &pTos[-pInstr->iP1+1]; - } -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force a string cast */ - if( (pNos->iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(pNos); - } - pCur = &pNos[1]; - while( pCur <= pTos ){ - if( (pCur->iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(pCur); - } - /* Perform the concatenation */ - if( SyBlobLength(&pCur->sBlob) > 0 ){ - jx9MemObjStringAppend(pNos, (const char *)SyBlobData(&pCur->sBlob), SyBlobLength(&pCur->sBlob)); - } - SyBlobRelease(&pCur->sBlob); - pCur++; - } - pTos = pNos; - break; - } -/* CAT_STORE: * * * - * - * Pop two elements from the stack. Concatenate them togeher and push the result - * back. - */ -case JX9_OP_CAT_STORE:{ - jx9_value *pNos = &pTos[-1]; - jx9_value *pObj; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - if((pTos->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(pTos); - } - if((pNos->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(pNos); - } - /* Perform the concatenation (Reverse order) */ - if( SyBlobLength(&pNos->sBlob) > 0 ){ - jx9MemObjStringAppend(pTos, (const char *)SyBlobData(&pNos->sBlob), SyBlobLength(&pNos->sBlob)); - } - /* Perform the store operation */ - if( pTos->nIdx == SXU32_HIGH ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "Cannot perform assignment on a constant object attribute"); - }else if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pTos->nIdx)) != 0 ){ - jx9MemObjStore(pTos, pObj); - } - jx9MemObjStore(pTos, pNos); - VmPopOperand(&pTos, 1); - break; - } -/* OP_AND: * * * - * - * Pop two values off the stack. Take the logical AND of the - * two values and push the resulting boolean value back onto the - * stack. - */ -/* OP_OR: * * * - * - * Pop two values off the stack. Take the logical OR of the - * two values and push the resulting boolean value back onto the - * stack. - */ -case JX9_OP_LAND: -case JX9_OP_LOR: { - jx9_value *pNos = &pTos[-1]; - sxi32 v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */ -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force a boolean cast */ - if((pTos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pTos); - } - if((pNos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pNos); - } - v1 = pNos->x.iVal == 0 ? 1 : 0; - v2 = pTos->x.iVal == 0 ? 1 : 0; - if( pInstr->iOp == JX9_OP_LAND ){ - static const unsigned char and_logic[] = { 0, 1, 2, 1, 1, 1, 2, 1, 2 }; - v1 = and_logic[v1*3+v2]; - }else{ - static const unsigned char or_logic[] = { 0, 0, 0, 0, 1, 2, 0, 2, 2 }; - v1 = or_logic[v1*3+v2]; - } - if( v1 == 2 ){ - v1 = 1; - } - VmPopOperand(&pTos, 1); - pTos->x.iVal = v1 == 0 ? 1 : 0; - MemObjSetType(pTos, MEMOBJ_BOOL); - break; - } -/* OP_LXOR: * * * - * - * Pop two values off the stack. Take the logical XOR of the - * two values and push the resulting boolean value back onto the - * stack. - * According to the JX9 language reference manual: - * $a xor $b is evaluated to TRUE if either $a or $b is - * TRUE, but not both. - */ -case JX9_OP_LXOR:{ - jx9_value *pNos = &pTos[-1]; - sxi32 v = 0; -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - /* Force a boolean cast */ - if((pTos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pTos); - } - if((pNos->iFlags & MEMOBJ_BOOL) == 0 ){ - jx9MemObjToBool(pNos); - } - if( (pNos->x.iVal && !pTos->x.iVal) || (pTos->x.iVal && !pNos->x.iVal) ){ - v = 1; - } - VmPopOperand(&pTos, 1); - pTos->x.iVal = v; - MemObjSetType(pTos, MEMOBJ_BOOL); - break; - } -/* OP_EQ P1 P2 P3 - * - * Pop the top two elements from the stack. If they are equal, then - * jump to instruction P2. Otherwise, continue to the next instruction. - * If P2 is zero, do not jump. Instead, push a boolean 1 (TRUE) onto the - * stack if the jump would have been taken, or a 0 (FALSE) if not. - */ -/* OP_NEQ P1 P2 P3 - * - * Pop the top two elements from the stack. If they are not equal, then - * jump to instruction P2. Otherwise, continue to the next instruction. - * If P2 is zero, do not jump. Instead, push a boolean 1 (TRUE) onto the - * stack if the jump would have been taken, or a 0 (FALSE) if not. - */ -case JX9_OP_EQ: -case JX9_OP_NEQ: { - jx9_value *pNos = &pTos[-1]; - /* Perform the comparison and act accordingly */ -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - rc = jx9MemObjCmp(pNos, pTos, FALSE, 0); - if( pInstr->iOp == JX9_OP_EQ ){ - rc = rc == 0; - }else{ - rc = rc != 0; - } - VmPopOperand(&pTos, 1); - if( !pInstr->iP2 ){ - /* Push comparison result without taking the jump */ - jx9MemObjRelease(pTos); - pTos->x.iVal = rc; - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_BOOL); - }else{ - if( rc ){ - /* Jump to the desired location */ - pc = pInstr->iP2 - 1; - VmPopOperand(&pTos, 1); - } - } - break; - } -/* OP_TEQ P1 P2 * - * - * Pop the top two elements from the stack. If they have the same type and are equal - * then jump to instruction P2. Otherwise, continue to the next instruction. - * If P2 is zero, do not jump. Instead, push a boolean 1 (TRUE) onto the - * stack if the jump would have been taken, or a 0 (FALSE) if not. - */ -case JX9_OP_TEQ: { - jx9_value *pNos = &pTos[-1]; - /* Perform the comparison and act accordingly */ -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - rc = jx9MemObjCmp(pNos, pTos, TRUE, 0) == 0; - VmPopOperand(&pTos, 1); - if( !pInstr->iP2 ){ - /* Push comparison result without taking the jump */ - jx9MemObjRelease(pTos); - pTos->x.iVal = rc; - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_BOOL); - }else{ - if( rc ){ - /* Jump to the desired location */ - pc = pInstr->iP2 - 1; - VmPopOperand(&pTos, 1); - } - } - break; - } -/* OP_TNE P1 P2 * - * - * Pop the top two elements from the stack.If they are not equal an they are not - * of the same type, then jump to instruction P2. Otherwise, continue to the next - * instruction. - * If P2 is zero, do not jump. Instead, push a boolean 1 (TRUE) onto the - * stack if the jump would have been taken, or a 0 (FALSE) if not. - * - */ -case JX9_OP_TNE: { - jx9_value *pNos = &pTos[-1]; - /* Perform the comparison and act accordingly */ -#ifdef UNTRUST - if( pNos < pStack ){ - goto Abort; - } -#endif - rc = jx9MemObjCmp(pNos, pTos, TRUE, 0) != 0; - VmPopOperand(&pTos, 1); - if( !pInstr->iP2 ){ - /* Push comparison result without taking the jump */ - jx9MemObjRelease(pTos); - pTos->x.iVal = rc; - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_BOOL); - }else{ - if( rc ){ - /* Jump to the desired location */ - pc = pInstr->iP2 - 1; - VmPopOperand(&pTos, 1); - } - } - break; - } -/* OP_LT P1 P2 P3 - * - * Pop the top two elements from the stack. If the second element (the top of stack) - * is less than the first (next on stack), then jump to instruction P2.Otherwise - * continue to the next instruction. In other words, jump if pNosiOp == JX9_OP_LE ){ - rc = rc < 1; - }else{ - rc = rc < 0; - } - VmPopOperand(&pTos, 1); - if( !pInstr->iP2 ){ - /* Push comparison result without taking the jump */ - jx9MemObjRelease(pTos); - pTos->x.iVal = rc; - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_BOOL); - }else{ - if( rc ){ - /* Jump to the desired location */ - pc = pInstr->iP2 - 1; - VmPopOperand(&pTos, 1); - } - } - break; - } -/* OP_GT P1 P2 P3 - * - * Pop the top two elements from the stack. If the second element (the top of stack) - * is greater than the first (next on stack), then jump to instruction P2.Otherwise - * continue to the next instruction. In other words, jump if pNosiOp == JX9_OP_GE ){ - rc = rc >= 0; - }else{ - rc = rc > 0; - } - VmPopOperand(&pTos, 1); - if( !pInstr->iP2 ){ - /* Push comparison result without taking the jump */ - jx9MemObjRelease(pTos); - pTos->x.iVal = rc; - /* Invalidate any prior representation */ - MemObjSetType(pTos, MEMOBJ_BOOL); - }else{ - if( rc ){ - /* Jump to the desired location */ - pc = pInstr->iP2 - 1; - VmPopOperand(&pTos, 1); - } - } - break; - } -/* - * OP_FOREACH_INIT * P2 P3 - * Prepare a foreach step. - */ -case JX9_OP_FOREACH_INIT: { - jx9_foreach_info *pInfo = (jx9_foreach_info *)pInstr->p3; - void *pName; -#ifdef UNTRUST - if( pTos < pStack ){ - goto Abort; - } -#endif - if( SyStringLength(&pInfo->sValue) < 1 ){ - /* Take the variable name from the top of the stack */ - if( (pTos->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(pTos); - } - /* Duplicate name */ - if( SyBlobLength(&pTos->sBlob) > 0 ){ - pName = SyMemBackendDup(&pVm->sAllocator, SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); - SyStringInitFromBuf(&pInfo->sValue, pName, SyBlobLength(&pTos->sBlob)); - } - VmPopOperand(&pTos, 1); - } - if( (pInfo->iFlags & JX9_4EACH_STEP_KEY) && SyStringLength(&pInfo->sKey) < 1 ){ - if( (pTos->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(pTos); - } - /* Duplicate name */ - if( SyBlobLength(&pTos->sBlob) > 0 ){ - pName = SyMemBackendDup(&pVm->sAllocator, SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); - SyStringInitFromBuf(&pInfo->sKey, pName, SyBlobLength(&pTos->sBlob)); - } - VmPopOperand(&pTos, 1); - } - /* Make sure we are dealing with a hashmap [i.e. JSON array or object ]*/ - if( (pTos->iFlags & (MEMOBJ_HASHMAP)) == 0 || SyStringLength(&pInfo->sValue) < 1 ){ - /* Jump out of the loop */ - if( (pTos->iFlags & MEMOBJ_NULL) == 0 ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_WARNING, - "Invalid argument supplied for the foreach statement, expecting JSON array or object instance"); - } - pc = pInstr->iP2 - 1; - }else{ - jx9_foreach_step *pStep; - pStep = (jx9_foreach_step *)SyMemBackendPoolAlloc(&pVm->sAllocator, sizeof(jx9_foreach_step)); - if( pStep == 0 ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "JX9 is running out of memory while preparing the 'foreach' step"); - /* Jump out of the loop */ - pc = pInstr->iP2 - 1; - }else{ - /* Zero the structure */ - SyZero(pStep, sizeof(jx9_foreach_step)); - /* Prepare the step */ - pStep->iFlags = pInfo->iFlags; - if( pTos->iFlags & MEMOBJ_HASHMAP ){ - jx9_hashmap *pMap = (jx9_hashmap *)pTos->x.pOther; - /* Reset the internal loop cursor */ - jx9HashmapResetLoopCursor(pMap); - /* Mark the step */ - pStep->pMap = pMap; - pMap->iRef++; - } - } - if( SXRET_OK != SySetPut(&pInfo->aStep, (const void *)&pStep) ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, "JX9 is running out of memory while preparing the 'foreach' step"); - SyMemBackendPoolFree(&pVm->sAllocator, pStep); - /* Jump out of the loop */ - pc = pInstr->iP2 - 1; - } - } - VmPopOperand(&pTos, 1); - break; - } -/* - * OP_FOREACH_STEP * P2 P3 - * Perform a foreach step. Jump to P2 at the end of the step. - */ -case JX9_OP_FOREACH_STEP: { - jx9_foreach_info *pInfo = (jx9_foreach_info *)pInstr->p3; - jx9_foreach_step **apStep, *pStep; - jx9_hashmap_node *pNode; - jx9_hashmap *pMap; - jx9_value *pValue; - /* Peek the last step */ - apStep = (jx9_foreach_step **)SySetBasePtr(&pInfo->aStep); - pStep = apStep[SySetUsed(&pInfo->aStep) - 1]; - pMap = pStep->pMap; - /* Extract the current node value */ - pNode = jx9HashmapGetNextEntry(pMap); - if( pNode == 0 ){ - /* No more entry to process */ - pc = pInstr->iP2 - 1; /* Jump to this destination */ - /* Automatically reset the loop cursor */ - jx9HashmapResetLoopCursor(pMap); - /* Cleanup the mess left behind */ - SyMemBackendPoolFree(&pVm->sAllocator, pStep); - SySetPop(&pInfo->aStep); - jx9HashmapUnref(pMap); - }else{ - if( (pStep->iFlags & JX9_4EACH_STEP_KEY) && SyStringLength(&pInfo->sKey) > 0 ){ - jx9_value *pKey = VmExtractMemObj(&(*pVm), &pInfo->sKey, FALSE, TRUE); - if( pKey ){ - jx9HashmapExtractNodeKey(pNode, pKey); - } - } - /* Make a copy of the entry value */ - pValue = VmExtractMemObj(&(*pVm), &pInfo->sValue, FALSE, TRUE); - if( pValue ){ - jx9HashmapExtractNodeValue(pNode, pValue, TRUE); - } - } - break; - } -/* - * OP_MEMBER P1 P2 - * Load JSON object entry on the stack. - */ -case JX9_OP_MEMBER: { - jx9_hashmap_node *pNode = 0; /* cc warning */ - jx9_hashmap *pMap = 0; - jx9_value *pIdx; - pIdx = pTos; - pTos--; - rc = SXERR_NOTFOUND; /* Assume the index is invalid */ - if( pTos->iFlags & MEMOBJ_HASHMAP ){ - /* Point to the hashmap */ - pMap = (jx9_hashmap *)pTos->x.pOther; - /* Load the desired entry */ - rc = jx9HashmapLookup(pMap, pIdx, &pNode); - } - jx9MemObjRelease(pIdx); - if( rc == SXRET_OK ){ - /* Load entry contents */ - if( pMap->iRef < 2 ){ - /* TICKET 1433-42: Array will be deleted shortly, so we will make a copy - * of the entry value, rather than pointing to it. - */ - pTos->nIdx = SXU32_HIGH; - jx9HashmapExtractNodeValue(pNode, pTos, TRUE); - }else{ - pTos->nIdx = pNode->nValIdx; - jx9HashmapExtractNodeValue(pNode, pTos, FALSE); - jx9HashmapUnref(pMap); - } - }else{ - /* No such entry, load NULL */ - jx9MemObjRelease(pTos); - pTos->nIdx = SXU32_HIGH; - } - break; - } -/* - * OP_SWITCH * * P3 - * This is the bytecode implementation of the complex switch() JX9 construct. - */ -case JX9_OP_SWITCH: { - jx9_switch *pSwitch = (jx9_switch *)pInstr->p3; - jx9_case_expr *aCase, *pCase; - jx9_value sValue, sCaseValue; - sxu32 n, nEntry; -#ifdef UNTRUST - if( pSwitch == 0 || pTos < pStack ){ - goto Abort; - } -#endif - /* Point to the case table */ - aCase = (jx9_case_expr *)SySetBasePtr(&pSwitch->aCaseExpr); - nEntry = SySetUsed(&pSwitch->aCaseExpr); - /* Select the appropriate case block to execute */ - jx9MemObjInit(pVm, &sValue); - jx9MemObjInit(pVm, &sCaseValue); - for( n = 0 ; n < nEntry ; ++n ){ - pCase = &aCase[n]; - jx9MemObjLoad(pTos, &sValue); - /* Execute the case expression first */ - VmLocalExec(pVm,&pCase->aByteCode, &sCaseValue); - /* Compare the two expression */ - rc = jx9MemObjCmp(&sValue, &sCaseValue, FALSE, 0); - jx9MemObjRelease(&sValue); - jx9MemObjRelease(&sCaseValue); - if( rc == 0 ){ - /* Value match, jump to this block */ - pc = pCase->nStart - 1; - break; - } - } - VmPopOperand(&pTos, 1); - if( n >= nEntry ){ - /* No approprite case to execute, jump to the default case */ - if( pSwitch->nDefault > 0 ){ - pc = pSwitch->nDefault - 1; - }else{ - /* No default case, jump out of this switch */ - pc = pSwitch->nOut - 1; - } - } - break; - } -/* - * OP_UPLINK P1 * * - * Link a variable to the top active VM frame. - * This is used to implement the 'uplink' JX9 construct. - */ -case JX9_OP_UPLINK: { - if( pVm->pFrame->pParent ){ - jx9_value *pLink = &pTos[-pInstr->iP1+1]; - SyString sName; - /* Perform the link */ - while( pLink <= pTos ){ - if((pLink->iFlags & MEMOBJ_STRING) == 0 ){ - /* Force a string cast */ - jx9MemObjToString(pLink); - } - SyStringInitFromBuf(&sName, SyBlobData(&pLink->sBlob), SyBlobLength(&pLink->sBlob)); - if( sName.nByte > 0 ){ - VmFrameLink(&(*pVm), &sName); - } - pLink++; - } - } - VmPopOperand(&pTos, pInstr->iP1); - break; - } -/* - * OP_CALL P1 * * - * Call a JX9 or a foreign function and push the return value of the called - * function on the stack. - */ -case JX9_OP_CALL: { - jx9_value *pArg = &pTos[-pInstr->iP1]; - SyHashEntry *pEntry; - SyString sName; - /* Extract function name */ - if( (pTos->iFlags & MEMOBJ_STRING) == 0 ){ - /* Raise exception: Invalid function name */ - VmErrorFormat(&(*pVm), JX9_CTX_WARNING, "Invalid function name, JX9 is returning NULL."); - /* Pop given arguments */ - if( pInstr->iP1 > 0 ){ - VmPopOperand(&pTos, pInstr->iP1); - } - /* Assume a null return value so that the program continue it's execution normally */ - jx9MemObjRelease(pTos); - break; - } - SyStringInitFromBuf(&sName, SyBlobData(&pTos->sBlob), SyBlobLength(&pTos->sBlob)); - /* Check for a compiled function first */ - pEntry = SyHashGet(&pVm->hFunction, (const void *)sName.zString, sName.nByte); - if( pEntry ){ - jx9_vm_func_arg *aFormalArg; - jx9_value *pFrameStack; - jx9_vm_func *pVmFunc; - VmFrame *pFrame; - jx9_value *pObj; - VmSlot sArg; - sxu32 n; - pVmFunc = (jx9_vm_func *)pEntry->pUserData; - /* Check The recursion limit */ - if( pVm->nRecursionDepth > pVm->nMaxDepth ){ - VmErrorFormat(&(*pVm), JX9_CTX_ERR, - "Recursion limit reached while invoking user function '%z', JX9 will set a NULL return value", - &pVmFunc->sName); - /* Pop given arguments */ - if( pInstr->iP1 > 0 ){ - VmPopOperand(&pTos, pInstr->iP1); - } - /* Assume a null return value so that the program continue it's execution normally */ - jx9MemObjRelease(pTos); - break; - } - if( pVmFunc->pNextName ){ - /* Function is candidate for overloading, select the appropriate function to call */ - pVmFunc = VmOverload(&(*pVm), pVmFunc, pArg, (int)(pTos-pArg)); - } - /* Extract the formal argument set */ - aFormalArg = (jx9_vm_func_arg *)SySetBasePtr(&pVmFunc->aArgs); - /* Create a new VM frame */ - rc = VmEnterFrame(&(*pVm),pVmFunc,&pFrame); - if( rc != SXRET_OK ){ - /* Raise exception: Out of memory */ - VmErrorFormat(&(*pVm), JX9_CTX_ERR, - "JX9 is running out of memory while calling function '%z', JX9 is returning NULL.", - &pVmFunc->sName); - /* Pop given arguments */ - if( pInstr->iP1 > 0 ){ - VmPopOperand(&pTos, pInstr->iP1); - } - /* Assume a null return value so that the program continue it's execution normally */ - jx9MemObjRelease(pTos); - break; - } - if( SySetUsed(&pVmFunc->aStatic) > 0 ){ - jx9_vm_func_static_var *pStatic, *aStatic; - /* Install static variables */ - aStatic = (jx9_vm_func_static_var *)SySetBasePtr(&pVmFunc->aStatic); - for( n = 0 ; n < SySetUsed(&pVmFunc->aStatic) ; ++n ){ - pStatic = &aStatic[n]; - if( pStatic->nIdx == SXU32_HIGH ){ - /* Initialize the static variables */ - pObj = VmReserveMemObj(&(*pVm), &pStatic->nIdx); - if( pObj ){ - /* Assume a NULL initialization value */ - jx9MemObjInit(&(*pVm), pObj); - if( SySetUsed(&pStatic->aByteCode) > 0 ){ - /* Evaluate initialization expression (Any complex expression) */ - VmLocalExec(&(*pVm), &pStatic->aByteCode, pObj); - } - pObj->nIdx = pStatic->nIdx; - }else{ - continue; - } - } - /* Install in the current frame */ - SyHashInsert(&pFrame->hVar, SyStringData(&pStatic->sName), SyStringLength(&pStatic->sName), - SX_INT_TO_PTR(pStatic->nIdx)); - } - } - /* Push arguments in the local frame */ - n = 0; - while( pArg < pTos ){ - if( n < SySetUsed(&pVmFunc->aArgs) ){ - if( (pArg->iFlags & MEMOBJ_NULL) && SySetUsed(&aFormalArg[n].aByteCode) > 0 ){ - /* NULL values are redirected to default arguments */ - rc = VmLocalExec(&(*pVm), &aFormalArg[n].aByteCode, pArg); - if( rc == JX9_ABORT ){ - goto Abort; - } - } - /* Make sure the given arguments are of the correct type */ - if( aFormalArg[n].nType > 0 ){ - if( ((pArg->iFlags & aFormalArg[n].nType) == 0) ){ - ProcMemObjCast xCast = jx9MemObjCastMethod(aFormalArg[n].nType); - /* Cast to the desired type */ - if( xCast ){ - xCast(pArg); - } - } - } - /* Pass by value, make a copy of the given argument */ - pObj = VmExtractMemObj(&(*pVm), &aFormalArg[n].sName, FALSE, TRUE); - }else{ - char zName[32]; - SyString sName; - /* Set a dummy name */ - sName.nByte = SyBufferFormat(zName, sizeof(zName), "[%u]apArg", n); - sName.zString = zName; - /* Annonymous argument */ - pObj = VmExtractMemObj(&(*pVm), &sName, TRUE, TRUE); - } - if( pObj ){ - jx9MemObjStore(pArg, pObj); - /* Insert argument index */ - sArg.nIdx = pObj->nIdx; - sArg.pUserData = 0; - SySetPut(&pFrame->sArg, (const void *)&sArg); - } - jx9MemObjRelease(pArg); - pArg++; - ++n; - } - /* Process default values */ - while( n < SySetUsed(&pVmFunc->aArgs) ){ - if( SySetUsed(&aFormalArg[n].aByteCode) > 0 ){ - pObj = VmExtractMemObj(&(*pVm), &aFormalArg[n].sName, FALSE, TRUE); - if( pObj ){ - /* Evaluate the default value and extract it's result */ - rc = VmLocalExec(&(*pVm), &aFormalArg[n].aByteCode, pObj); - if( rc == JX9_ABORT ){ - goto Abort; - } - /* Insert argument index */ - sArg.nIdx = pObj->nIdx; - sArg.pUserData = 0; - SySetPut(&pFrame->sArg, (const void *)&sArg); - /* Make sure the default argument is of the correct type */ - if( aFormalArg[n].nType > 0 && ((pObj->iFlags & aFormalArg[n].nType) == 0) ){ - ProcMemObjCast xCast = jx9MemObjCastMethod(aFormalArg[n].nType); - /* Cast to the desired type */ - xCast(pObj); - } - } - } - ++n; - } - /* Pop arguments, function name from the operand stack and assume the function - * does not return anything. - */ - jx9MemObjRelease(pTos); - pTos = &pTos[-pInstr->iP1]; - /* Allocate a new operand stack and evaluate the function body */ - pFrameStack = VmNewOperandStack(&(*pVm), SySetUsed(&pVmFunc->aByteCode)); - if( pFrameStack == 0 ){ - /* Raise exception: Out of memory */ - VmErrorFormat(&(*pVm), JX9_CTX_ERR, "JX9 is running out of memory while calling function '%z', JX9 is returning NULL.", - &pVmFunc->sName); - if( pInstr->iP1 > 0 ){ - VmPopOperand(&pTos, pInstr->iP1); - } - break; - } - /* Increment nesting level */ - pVm->nRecursionDepth++; - /* Execute function body */ - rc = VmByteCodeExec(&(*pVm), (VmInstr *)SySetBasePtr(&pVmFunc->aByteCode), pFrameStack, -1, pTos); - /* Decrement nesting level */ - pVm->nRecursionDepth--; - /* Free the operand stack */ - SyMemBackendFree(&pVm->sAllocator, pFrameStack); - /* Leave the frame */ - VmLeaveFrame(&(*pVm)); - if( rc == JX9_ABORT ){ - /* Abort processing immeditaley */ - goto Abort; - } - }else{ - jx9_user_func *pFunc; - jx9_context sCtx; - jx9_value sRet; - /* Look for an installed foreign function */ - pEntry = SyHashGet(&pVm->hHostFunction, (const void *)sName.zString, sName.nByte); - if( pEntry == 0 ){ - /* Call to undefined function */ - VmErrorFormat(&(*pVm), JX9_CTX_WARNING, "Call to undefined function '%z', JX9 is returning NULL.", &sName); - /* Pop given arguments */ - if( pInstr->iP1 > 0 ){ - VmPopOperand(&pTos, pInstr->iP1); - } - /* Assume a null return value so that the program continue it's execution normally */ - jx9MemObjRelease(pTos); - break; - } - pFunc = (jx9_user_func *)pEntry->pUserData; - /* Start collecting function arguments */ - SySetReset(&aArg); - while( pArg < pTos ){ - SySetPut(&aArg, (const void *)&pArg); - pArg++; - } - /* Assume a null return value */ - jx9MemObjInit(&(*pVm), &sRet); - /* Init the call context */ - VmInitCallContext(&sCtx, &(*pVm), pFunc, &sRet, 0); - /* Call the foreign function */ - rc = pFunc->xFunc(&sCtx, (int)SySetUsed(&aArg), (jx9_value **)SySetBasePtr(&aArg)); - /* Release the call context */ - VmReleaseCallContext(&sCtx); - if( rc == JX9_ABORT ){ - goto Abort; - } - if( pInstr->iP1 > 0 ){ - /* Pop function name and arguments */ - VmPopOperand(&pTos, pInstr->iP1); - } - /* Save foreign function return value */ - jx9MemObjStore(&sRet, pTos); - jx9MemObjRelease(&sRet); - } - break; - } -/* - * OP_CONSUME: P1 * * - * Consume (Invoke the installed VM output consumer callback) and POP P1 elements from the stack. - */ -case JX9_OP_CONSUME: { - jx9_output_consumer *pCons = &pVm->sVmConsumer; - jx9_value *pCur, *pOut = pTos; - - pOut = &pTos[-pInstr->iP1 + 1]; - pCur = pOut; - /* Start the consume process */ - while( pOut <= pTos ){ - /* Force a string cast */ - if( (pOut->iFlags & MEMOBJ_STRING) == 0 ){ - jx9MemObjToString(pOut); - } - if( SyBlobLength(&pOut->sBlob) > 0 ){ - /*SyBlobNullAppend(&pOut->sBlob);*/ - /* Invoke the output consumer callback */ - rc = pCons->xConsumer(SyBlobData(&pOut->sBlob), SyBlobLength(&pOut->sBlob), pCons->pUserData); - /* Increment output length */ - pVm->nOutputLen += SyBlobLength(&pOut->sBlob); - SyBlobRelease(&pOut->sBlob); - if( rc == SXERR_ABORT ){ - /* Output consumer callback request an operation abort. */ - goto Abort; - } - } - pOut++; - } - pTos = &pCur[-1]; - break; - } - - } /* Switch() */ - pc++; /* Next instruction in the stream */ - } /* For(;;) */ -Done: - SySetRelease(&aArg); - return SXRET_OK; -Abort: - SySetRelease(&aArg); - while( pTos >= pStack ){ - jx9MemObjRelease(pTos); - pTos--; - } - return JX9_ABORT; -} -/* - * Execute as much of a local JX9 bytecode program as we can then return. - * This function is a wrapper around [VmByteCodeExec()]. - * See block-comment on that function for additional information. - */ -static sxi32 VmLocalExec(jx9_vm *pVm, SySet *pByteCode,jx9_value *pResult) -{ - jx9_value *pStack; - sxi32 rc; - /* Allocate a new operand stack */ - pStack = VmNewOperandStack(&(*pVm), SySetUsed(pByteCode)); - if( pStack == 0 ){ - return SXERR_MEM; - } - /* Execute the program */ - rc = VmByteCodeExec(&(*pVm), (VmInstr *)SySetBasePtr(pByteCode), pStack, -1, &(*pResult)); - /* Free the operand stack */ - SyMemBackendFree(&pVm->sAllocator, pStack); - /* Execution result */ - return rc; -} -/* - * Execute as much of a JX9 bytecode program as we can then return. - * This function is a wrapper around [VmByteCodeExec()]. - * See block-comment on that function for additional information. - */ -JX9_PRIVATE sxi32 jx9VmByteCodeExec(jx9_vm *pVm) -{ - /* Make sure we are ready to execute this program */ - if( pVm->nMagic != JX9_VM_RUN ){ - return pVm->nMagic == JX9_VM_EXEC ? SXERR_LOCKED /* Locked VM */ : SXERR_CORRUPT; /* Stale VM */ - } - /* Set the execution magic number */ - pVm->nMagic = JX9_VM_EXEC; - /* Execute the program */ - VmByteCodeExec(&(*pVm), (VmInstr *)SySetBasePtr(pVm->pByteContainer), pVm->aOps, -1, &pVm->sExec); - /* - * TICKET 1433-100: Do not remove the JX9_VM_EXEC magic number - * so that any following call to [jx9_vm_exec()] without calling - * [jx9_vm_reset()] first would fail. - */ - return SXRET_OK; -} -/* - * Extract a memory object (i.e. a variable) from the running script. - * This function must be called after calling jx9_vm_exec(). Otherwise - * NULL is returned. - */ -JX9_PRIVATE jx9_value * jx9VmExtractVariable(jx9_vm *pVm,SyString *pVar) -{ - jx9_value *pValue; - if( pVm->nMagic != JX9_VM_EXEC ){ - /* call jx9_vm_exec() first */ - return 0; - } - /* Perform the lookup */ - pValue = VmExtractMemObj(pVm,pVar,FALSE,FALSE); - /* Lookup result */ - return pValue; -} -/* - * Invoke the installed VM output consumer callback to consume - * the desired message. - * Refer to the implementation of [jx9_context_output()] defined - * in 'api.c' for additional information. - */ -JX9_PRIVATE sxi32 jx9VmOutputConsume( - jx9_vm *pVm, /* Target VM */ - SyString *pString /* Message to output */ - ) -{ - jx9_output_consumer *pCons = &pVm->sVmConsumer; - sxi32 rc = SXRET_OK; - /* Call the output consumer */ - if( pString->nByte > 0 ){ - rc = pCons->xConsumer((const void *)pString->zString, pString->nByte, pCons->pUserData); - /* Increment output length */ - pVm->nOutputLen += pString->nByte; - } - return rc; -} -/* - * Format a message and invoke the installed VM output consumer - * callback to consume the formatted message. - * Refer to the implementation of [jx9_context_output_format()] defined - * in 'api.c' for additional information. - */ -JX9_PRIVATE sxi32 jx9VmOutputConsumeAp( - jx9_vm *pVm, /* Target VM */ - const char *zFormat, /* Formatted message to output */ - va_list ap /* Variable list of arguments */ - ) -{ - jx9_output_consumer *pCons = &pVm->sVmConsumer; - sxi32 rc = SXRET_OK; - SyBlob sWorker; - /* Format the message and call the output consumer */ - SyBlobInit(&sWorker, &pVm->sAllocator); - SyBlobFormatAp(&sWorker, zFormat, ap); - if( SyBlobLength(&sWorker) > 0 ){ - /* Consume the formatted message */ - rc = pCons->xConsumer(SyBlobData(&sWorker), SyBlobLength(&sWorker), pCons->pUserData); - } - /* Increment output length */ - pVm->nOutputLen += SyBlobLength(&sWorker); - /* Release the working buffer */ - SyBlobRelease(&sWorker); - return rc; -} -/* - * Return a string representation of the given JX9 OP code. - * This function never fail and always return a pointer - * to a null terminated string. - */ -static const char * VmInstrToString(sxi32 nOp) -{ - const char *zOp = "Unknown "; - switch(nOp){ - case JX9_OP_DONE: zOp = "DONE "; break; - case JX9_OP_HALT: zOp = "HALT "; break; - case JX9_OP_LOAD: zOp = "LOAD "; break; - case JX9_OP_LOADC: zOp = "LOADC "; break; - case JX9_OP_LOAD_MAP: zOp = "LOAD_MAP "; break; - case JX9_OP_LOAD_IDX: zOp = "LOAD_IDX "; break; - case JX9_OP_NOOP: zOp = "NOOP "; break; - case JX9_OP_JMP: zOp = "JMP "; break; - case JX9_OP_JZ: zOp = "JZ "; break; - case JX9_OP_JNZ: zOp = "JNZ "; break; - case JX9_OP_POP: zOp = "POP "; break; - case JX9_OP_CAT: zOp = "CAT "; break; - case JX9_OP_CVT_INT: zOp = "CVT_INT "; break; - case JX9_OP_CVT_STR: zOp = "CVT_STR "; break; - case JX9_OP_CVT_REAL: zOp = "CVT_REAL "; break; - case JX9_OP_CALL: zOp = "CALL "; break; - case JX9_OP_UMINUS: zOp = "UMINUS "; break; - case JX9_OP_UPLUS: zOp = "UPLUS "; break; - case JX9_OP_BITNOT: zOp = "BITNOT "; break; - case JX9_OP_LNOT: zOp = "LOGNOT "; break; - case JX9_OP_MUL: zOp = "MUL "; break; - case JX9_OP_DIV: zOp = "DIV "; break; - case JX9_OP_MOD: zOp = "MOD "; break; - case JX9_OP_ADD: zOp = "ADD "; break; - case JX9_OP_SUB: zOp = "SUB "; break; - case JX9_OP_SHL: zOp = "SHL "; break; - case JX9_OP_SHR: zOp = "SHR "; break; - case JX9_OP_LT: zOp = "LT "; break; - case JX9_OP_LE: zOp = "LE "; break; - case JX9_OP_GT: zOp = "GT "; break; - case JX9_OP_GE: zOp = "GE "; break; - case JX9_OP_EQ: zOp = "EQ "; break; - case JX9_OP_NEQ: zOp = "NEQ "; break; - case JX9_OP_TEQ: zOp = "TEQ "; break; - case JX9_OP_TNE: zOp = "TNE "; break; - case JX9_OP_BAND: zOp = "BITAND "; break; - case JX9_OP_BXOR: zOp = "BITXOR "; break; - case JX9_OP_BOR: zOp = "BITOR "; break; - case JX9_OP_LAND: zOp = "LOGAND "; break; - case JX9_OP_LOR: zOp = "LOGOR "; break; - case JX9_OP_LXOR: zOp = "LOGXOR "; break; - case JX9_OP_STORE: zOp = "STORE "; break; - case JX9_OP_STORE_IDX: zOp = "STORE_IDX "; break; - case JX9_OP_PULL: zOp = "PULL "; break; - case JX9_OP_SWAP: zOp = "SWAP "; break; - case JX9_OP_YIELD: zOp = "YIELD "; break; - case JX9_OP_CVT_BOOL: zOp = "CVT_BOOL "; break; - case JX9_OP_CVT_NULL: zOp = "CVT_NULL "; break; - case JX9_OP_CVT_ARRAY: zOp = "CVT_JSON "; break; - case JX9_OP_CVT_NUMC: zOp = "CVT_NUMC "; break; - case JX9_OP_INCR: zOp = "INCR "; break; - case JX9_OP_DECR: zOp = "DECR "; break; - case JX9_OP_ADD_STORE: zOp = "ADD_STORE "; break; - case JX9_OP_SUB_STORE: zOp = "SUB_STORE "; break; - case JX9_OP_MUL_STORE: zOp = "MUL_STORE "; break; - case JX9_OP_DIV_STORE: zOp = "DIV_STORE "; break; - case JX9_OP_MOD_STORE: zOp = "MOD_STORE "; break; - case JX9_OP_CAT_STORE: zOp = "CAT_STORE "; break; - case JX9_OP_SHL_STORE: zOp = "SHL_STORE "; break; - case JX9_OP_SHR_STORE: zOp = "SHR_STORE "; break; - case JX9_OP_BAND_STORE: zOp = "BAND_STORE "; break; - case JX9_OP_BOR_STORE: zOp = "BOR_STORE "; break; - case JX9_OP_BXOR_STORE: zOp = "BXOR_STORE "; break; - case JX9_OP_CONSUME: zOp = "CONSUME "; break; - case JX9_OP_MEMBER: zOp = "MEMBER "; break; - case JX9_OP_UPLINK: zOp = "UPLINK "; break; - case JX9_OP_SWITCH: zOp = "SWITCH "; break; - case JX9_OP_FOREACH_INIT: - zOp = "4EACH_INIT "; break; - case JX9_OP_FOREACH_STEP: - zOp = "4EACH_STEP "; break; - default: - break; - } - return zOp; -} -/* - * Dump JX9 bytecodes instructions to a human readable format. - * The xConsumer() callback which is an used defined function - * is responsible of consuming the generated dump. - */ -JX9_PRIVATE sxi32 jx9VmDump( - jx9_vm *pVm, /* Target VM */ - ProcConsumer xConsumer, /* Output [i.e: dump] consumer callback */ - void *pUserData /* Last argument to xConsumer() */ - ) -{ - sxi32 rc; - rc = VmByteCodeDump(pVm->pByteContainer, xConsumer, pUserData); - return rc; -} -/* - * Default constant expansion callback used by the 'const' statement if used - * outside a object body [i.e: global or function scope]. - * Refer to the implementation of [JX9_CompileConstant()] defined - * in 'compile.c' for additional information. - */ -JX9_PRIVATE void jx9VmExpandConstantValue(jx9_value *pVal, void *pUserData) -{ - SySet *pByteCode = (SySet *)pUserData; - /* Evaluate and expand constant value */ - VmLocalExec((jx9_vm *)SySetGetUserData(pByteCode), pByteCode, (jx9_value *)pVal); -} -/* - * Section: - * Function handling functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * int func_num_args(void) - * Returns the number of arguments passed to the function. - * Parameters - * None. - * Return - * Total number of arguments passed into the current user-defined function - * or -1 if called from the globe scope. - */ -static int vm_builtin_func_num_args(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - VmFrame *pFrame; - jx9_vm *pVm; - /* Point to the target VM */ - pVm = pCtx->pVm; - /* Current frame */ - pFrame = pVm->pFrame; - if( pFrame->pParent == 0 ){ - SXUNUSED(nArg); - SXUNUSED(apArg); - /* Global frame, return -1 */ - jx9_result_int(pCtx, -1); - return SXRET_OK; - } - /* Total number of arguments passed to the enclosing function */ - nArg = (int)SySetUsed(&pFrame->sArg); - jx9_result_int(pCtx, nArg); - return SXRET_OK; -} -/* - * value func_get_arg(int $arg_num) - * Return an item from the argument list. - * Parameters - * Argument number(index start from zero). - * Return - * Returns the specified argument or FALSE on error. - */ -static int vm_builtin_func_get_arg(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pObj = 0; - VmSlot *pSlot = 0; - VmFrame *pFrame; - jx9_vm *pVm; - /* Point to the target VM */ - pVm = pCtx->pVm; - /* Current frame */ - pFrame = pVm->pFrame; - if( nArg < 1 || pFrame->pParent == 0 ){ - /* Global frame or Missing arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Called in the global scope"); - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Extract the desired index */ - nArg = jx9_value_to_int(apArg[0]); - if( nArg < 0 || nArg >= (int)SySetUsed(&pFrame->sArg) ){ - /* Invalid index, return FALSE */ - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Extract the desired argument */ - if( (pSlot = (VmSlot *)SySetAt(&pFrame->sArg, (sxu32)nArg)) != 0 ){ - if( (pObj = (jx9_value *)SySetAt(&pVm->aMemObj, pSlot->nIdx)) != 0 ){ - /* Return the desired argument */ - jx9_result_value(pCtx, (jx9_value *)pObj); - }else{ - /* No such argument, return false */ - jx9_result_bool(pCtx, 0); - } - }else{ - /* CAN'T HAPPEN */ - jx9_result_bool(pCtx, 0); - } - return SXRET_OK; -} -/* - * array func_get_args(void) - * Returns an array comprising a copy of function's argument list. - * Parameters - * None. - * Return - * Returns an array in which each element is a copy of the corresponding - * member of the current user-defined function's argument list. - * Otherwise FALSE is returned on failure. - */ -static int vm_builtin_func_get_args(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pObj = 0; - jx9_value *pArray; - VmFrame *pFrame; - VmSlot *aSlot; - sxu32 n; - /* Point to the current frame */ - pFrame = pCtx->pVm->pFrame; - if( pFrame->pParent == 0 ){ - /* Global frame, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_WARNING, "Called in the global scope"); - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Create a new array */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Start filling the array with the given arguments */ - aSlot = (VmSlot *)SySetBasePtr(&pFrame->sArg); - for( n = 0; n < SySetUsed(&pFrame->sArg) ; n++ ){ - pObj = (jx9_value *)SySetAt(&pCtx->pVm->aMemObj, aSlot[n].nIdx); - if( pObj ){ - jx9_array_add_elem(pArray, 0/* Automatic index assign*/, pObj); - } - } - /* Return the freshly created array */ - jx9_result_value(pCtx, pArray); - return SXRET_OK; -} -/* - * bool function_exists(string $name) - * Return TRUE if the given function has been defined. - * Parameters - * The name of the desired function. - * Return - * Return TRUE if the given function has been defined.False otherwise - */ -static int vm_builtin_func_exists(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zName; - jx9_vm *pVm; - int nLen; - int res; - if( nArg < 1 ){ - /* Missing argument, return FALSE */ - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Point to the target VM */ - pVm = pCtx->pVm; - /* Extract the function name */ - zName = jx9_value_to_string(apArg[0], &nLen); - /* Assume the function is not defined */ - res = 0; - /* Perform the lookup */ - if( SyHashGet(&pVm->hFunction, (const void *)zName, (sxu32)nLen) != 0 || - SyHashGet(&pVm->hHostFunction, (const void *)zName, (sxu32)nLen) != 0 ){ - /* Function is defined */ - res = 1; - } - jx9_result_bool(pCtx, res); - return SXRET_OK; -} -/* - * Verify that the contents of a variable can be called as a function. - * [i.e: Whether it is callable or not]. - * Return TRUE if callable.FALSE otherwise. - */ -JX9_PRIVATE int jx9VmIsCallable(jx9_vm *pVm, jx9_value *pValue) -{ - int res = 0; - if( pValue->iFlags & MEMOBJ_STRING ){ - const char *zName; - int nLen; - /* Extract the name */ - zName = jx9_value_to_string(pValue, &nLen); - /* Perform the lookup */ - if( SyHashGet(&pVm->hFunction, (const void *)zName, (sxu32)nLen) != 0 || - SyHashGet(&pVm->hHostFunction, (const void *)zName, (sxu32)nLen) != 0 ){ - /* Function is callable */ - res = 1; - } - } - return res; -} -/* - * bool is_callable(callable $name[, bool $syntax_only = false]) - * Verify that the contents of a variable can be called as a function. - * Parameters - * $name - * The callback function to check - * $syntax_only - * If set to TRUE the function only verifies that name might be a function or method. - * It will only reject simple variables that are not strings, or an array that does - * not have a valid structure to be used as a callback. The valid ones are supposed - * to have only 2 entries, the first of which is an object or a string, and the second - * a string. - * Return - * TRUE if name is callable, FALSE otherwise. - */ -static int vm_builtin_is_callable(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_vm *pVm; - int res; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Point to the target VM */ - pVm = pCtx->pVm; - /* Perform the requested operation */ - res = jx9VmIsCallable(pVm, apArg[0]); - jx9_result_bool(pCtx, res); - return SXRET_OK; -} -/* - * Hash walker callback used by the [get_defined_functions()] function - * defined below. - */ -static int VmHashFuncStep(SyHashEntry *pEntry, void *pUserData) -{ - jx9_value *pArray = (jx9_value *)pUserData; - jx9_value sName; - sxi32 rc; - /* Prepare the function name for insertion */ - jx9MemObjInitFromString(pArray->pVm, &sName, 0); - jx9MemObjStringAppend(&sName, (const char *)pEntry->pKey, pEntry->nKeyLen); - /* Perform the insertion */ - rc = jx9_array_add_elem(pArray, 0/* Automatic index assign */, &sName); /* Will make it's own copy */ - jx9MemObjRelease(&sName); - return rc; -} -/* - * array get_defined_functions(void) - * Returns an array of all defined functions. - * Parameter - * None. - * Return - * Returns an multidimensional array containing a list of all defined functions - * both built-in (internal) and user-defined. - * The internal functions will be accessible via $arr["internal"], and the user - * defined ones using $arr["user"]. - * Note: - * NULL is returned on failure. - */ -static int vm_builtin_get_defined_func(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray; - /* NOTE: - * Don't worry about freeing memory here, every allocated resource will be released - * automatically by the engine as soon we return from this foreign function. - */ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* Return NULL */ - jx9_result_null(pCtx); - return SXRET_OK; - } - /* Fill with the appropriate information */ - SyHashForEach(&pCtx->pVm->hHostFunction,VmHashFuncStep,pArray); - /* Fill with the appropriate information */ - SyHashForEach(&pCtx->pVm->hFunction, VmHashFuncStep,pArray); - /* Return a copy of the array array */ - jx9_result_value(pCtx, pArray); - return SXRET_OK; -} -/* - * Call a user defined or foreign function where the name of the function - * is stored in the pFunc parameter and the given arguments are stored - * in the apArg[] array. - * Return SXRET_OK if the function was successfuly called.Any other - * return value indicates failure. - */ -JX9_PRIVATE sxi32 jx9VmCallUserFunction( - jx9_vm *pVm, /* Target VM */ - jx9_value *pFunc, /* Callback name */ - int nArg, /* Total number of given arguments */ - jx9_value **apArg, /* Callback arguments */ - jx9_value *pResult /* Store callback return value here. NULL otherwise */ - ) -{ - jx9_value *aStack; - VmInstr aInstr[2]; - int i; - if((pFunc->iFlags & (MEMOBJ_STRING)) == 0 ){ - /* Don't bother processing, it's invalid anyway */ - if( pResult ){ - /* Assume a null return value */ - jx9MemObjRelease(pResult); - } - return SXERR_INVALID; - } - /* Create a new operand stack */ - aStack = VmNewOperandStack(&(*pVm), 1+nArg); - if( aStack == 0 ){ - jx9VmThrowError(&(*pVm), 0, JX9_CTX_ERR, - "JX9 is running out of memory while invoking user callback"); - if( pResult ){ - /* Assume a null return value */ - jx9MemObjRelease(pResult); - } - return SXERR_MEM; - } - /* Fill the operand stack with the given arguments */ - for( i = 0 ; i < nArg ; i++ ){ - jx9MemObjLoad(apArg[i], &aStack[i]); - aStack[i].nIdx = apArg[i]->nIdx; - } - /* Push the function name */ - jx9MemObjLoad(pFunc, &aStack[i]); - aStack[i].nIdx = SXU32_HIGH; /* Mark as constant */ - /* Emit the CALL istruction */ - aInstr[0].iOp = JX9_OP_CALL; - aInstr[0].iP1 = nArg; /* Total number of given arguments */ - aInstr[0].iP2 = 0; - aInstr[0].p3 = 0; - /* Emit the DONE instruction */ - aInstr[1].iOp = JX9_OP_DONE; - aInstr[1].iP1 = 1; /* Extract function return value if available */ - aInstr[1].iP2 = 0; - aInstr[1].p3 = 0; - /* Execute the function body (if available) */ - VmByteCodeExec(&(*pVm), aInstr, aStack, nArg, pResult); - /* Clean up the mess left behind */ - SyMemBackendFree(&pVm->sAllocator, aStack); - return JX9_OK; -} -/* - * Call a user defined or foreign function whith a varibale number - * of arguments where the name of the function is stored in the pFunc - * parameter. - * Return SXRET_OK if the function was successfuly called.Any other - * return value indicates failure. - */ -JX9_PRIVATE sxi32 jx9VmCallUserFunctionAp( - jx9_vm *pVm, /* Target VM */ - jx9_value *pFunc, /* Callback name */ - jx9_value *pResult, /* Store callback return value here. NULL otherwise */ - ... /* 0 (Zero) or more Callback arguments */ - ) -{ - jx9_value *pArg; - SySet aArg; - va_list ap; - sxi32 rc; - SySetInit(&aArg, &pVm->sAllocator, sizeof(jx9_value *)); - /* Copy arguments one after one */ - va_start(ap, pResult); - for(;;){ - pArg = va_arg(ap, jx9_value *); - if( pArg == 0 ){ - break; - } - SySetPut(&aArg, (const void *)&pArg); - } - /* Call the core routine */ - rc = jx9VmCallUserFunction(&(*pVm), pFunc, (int)SySetUsed(&aArg), (jx9_value **)SySetBasePtr(&aArg), pResult); - /* Cleanup */ - SySetRelease(&aArg); - return rc; -} -/* - * bool defined(string $name) - * Checks whether a given named constant exists. - * Parameter: - * Name of the desired constant. - * Return - * TRUE if the given constant exists.FALSE otherwise. - */ -static int vm_builtin_defined(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zName; - int nLen = 0; - int res = 0; - if( nArg < 1 ){ - /* Missing constant name, return FALSE */ - jx9_context_throw_error(pCtx,JX9_CTX_NOTICE,"Missing constant name"); - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - /* Extract constant name */ - zName = jx9_value_to_string(apArg[0], &nLen); - /* Perform the lookup */ - if( nLen > 0 && SyHashGet(&pCtx->pVm->hConstant, (const void *)zName, (sxu32)nLen) != 0 ){ - /* Already defined */ - res = 1; - } - jx9_result_bool(pCtx, res); - return SXRET_OK; -} -/* - * Hash walker callback used by the [get_defined_constants()] function - * defined below. - */ -static int VmHashConstStep(SyHashEntry *pEntry, void *pUserData) -{ - jx9_value *pArray = (jx9_value *)pUserData; - jx9_value sName; - sxi32 rc; - /* Prepare the constant name for insertion */ - jx9MemObjInitFromString(pArray->pVm, &sName, 0); - jx9MemObjStringAppend(&sName, (const char *)pEntry->pKey, pEntry->nKeyLen); - /* Perform the insertion */ - rc = jx9_array_add_elem(pArray, 0, &sName); /* Will make it's own copy */ - jx9MemObjRelease(&sName); - return rc; -} -/* - * array get_defined_constants(void) - * Returns an associative array with the names of all defined - * constants. - * Parameters - * NONE. - * Returns - * Returns the names of all the constants currently defined. - */ -static int vm_builtin_get_defined_constants(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - jx9_value *pArray; - /* Create the array first*/ - pArray = jx9_context_new_array(pCtx); - if( pArray == 0 ){ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - /* Return NULL */ - jx9_result_null(pCtx); - return SXRET_OK; - } - /* Fill the array with the defined constants */ - SyHashForEach(&pCtx->pVm->hConstant, VmHashConstStep, pArray); - /* Return the created array */ - jx9_result_value(pCtx, pArray); - return SXRET_OK; -} -/* - * Section: - * Random numbers/string generators. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * Generate a random 32-bit unsigned integer. - * JX9 use it's own private PRNG which is based on the one - * used by te SQLite3 library. - */ -JX9_PRIVATE sxu32 jx9VmRandomNum(jx9_vm *pVm) -{ - sxu32 iNum; - SyRandomness(&pVm->sPrng, (void *)&iNum, sizeof(sxu32)); - return iNum; -} -/* - * Generate a random string (English Alphabet) of length nLen. - * Note that the generated string is NOT null terminated. - * JX9 use it's own private PRNG which is based on the one used - * by te SQLite3 library. - */ -JX9_PRIVATE void jx9VmRandomString(jx9_vm *pVm, char *zBuf, int nLen) -{ - static const char zBase[] = {"abcdefghijklmnopqrstuvwxyz"}; /* English Alphabet */ - int i; - /* Generate a binary string first */ - SyRandomness(&pVm->sPrng, zBuf, (sxu32)nLen); - /* Turn the binary string into english based alphabet */ - for( i = 0 ; i < nLen ; ++i ){ - zBuf[i] = zBase[zBuf[i] % (sizeof(zBase)-1)]; - } -} -/* - * int rand() - * Generate a random (unsigned 32-bit) integer. - * Parameter - * $min - * The lowest value to return (default: 0) - * $max - * The highest value to return (default: getrandmax()) - * Return - * A pseudo random value between min (or 0) and max (or getrandmax(), inclusive). - * Note: - * JX9 use it's own private PRNG which is based on the one used - * by te SQLite3 library. - */ -static int vm_builtin_rand(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - sxu32 iNum; - /* Generate the random number */ - iNum = jx9VmRandomNum(pCtx->pVm); - if( nArg > 1 ){ - sxu32 iMin, iMax; - iMin = (sxu32)jx9_value_to_int(apArg[0]); - iMax = (sxu32)jx9_value_to_int(apArg[1]); - if( iMin < iMax ){ - sxu32 iDiv = iMax+1-iMin; - if( iDiv > 0 ){ - iNum = (iNum % iDiv)+iMin; - } - }else if(iMax > 0 ){ - iNum %= iMax; - } - } - /* Return the number */ - jx9_result_int64(pCtx, (jx9_int64)iNum); - return SXRET_OK; -} -/* - * int getrandmax(void) - * Show largest possible random value - * Return - * The largest possible random value returned by rand() which is in - * this implementation 0xFFFFFFFF. - * Note: - * JX9 use it's own private PRNG which is based on the one used - * by te SQLite3 library. - */ -static int vm_builtin_getrandmax(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SXUNUSED(nArg); /* cc warning */ - SXUNUSED(apArg); - jx9_result_int64(pCtx, SXU32_HIGH); - return SXRET_OK; -} -/* - * string rand_str() - * string rand_str(int $len) - * Generate a random string (English alphabet). - * Parameter - * $len - * Length of the desired string (default: 16, Min: 1, Max: 1024) - * Return - * A pseudo random string. - * Note: - * JX9 use it's own private PRNG which is based on the one used - * by te SQLite3 library. - */ -static int vm_builtin_rand_str(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - char zString[1024]; - int iLen = 0x10; - if( nArg > 0 ){ - /* Get the desired length */ - iLen = jx9_value_to_int(apArg[0]); - if( iLen < 1 || iLen > 1024 ){ - /* Default length */ - iLen = 0x10; - } - } - /* Generate the random string */ - jx9VmRandomString(pCtx->pVm, zString, iLen); - /* Return the generated string */ - jx9_result_string(pCtx, zString, iLen); /* Will make it's own copy */ - return SXRET_OK; -} -/* - * Section: - * Language construct implementation as foreign functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * void print($string...) - * Output one or more messages. - * Parameters - * $string - * Message to output. - * Return - * NULL. - */ -static int vm_builtin_print(jx9_context *pCtx, int nArg,jx9_value **apArg) -{ - const char *zData; - int nDataLen = 0; - jx9_vm *pVm; - int i, rc; - /* Point to the target VM */ - pVm = pCtx->pVm; - /* Output */ - for( i = 0 ; i < nArg ; ++i ){ - zData = jx9_value_to_string(apArg[i], &nDataLen); - if( nDataLen > 0 ){ - rc = pVm->sVmConsumer.xConsumer((const void *)zData, (unsigned int)nDataLen, pVm->sVmConsumer.pUserData); - /* Increment output length */ - pVm->nOutputLen += nDataLen; - if( rc == SXERR_ABORT ){ - /* Output consumer callback request an operation abort */ - return JX9_ABORT; - } - } - } - return SXRET_OK; -} -/* - * void exit(string $msg) - * void exit(int $status) - * void die(string $ms) - * void die(int $status) - * Output a message and terminate program execution. - * Parameter - * If status is a string, this function prints the status just before exiting. - * If status is an integer, that value will be used as the exit status - * and not printed - * Return - * NULL - */ -static int vm_builtin_exit(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg > 0 ){ - if( jx9_value_is_string(apArg[0]) ){ - const char *zData; - int iLen = 0; - /* Print exit message */ - zData = jx9_value_to_string(apArg[0], &iLen); - jx9_context_output(pCtx, zData, iLen); - }else if(jx9_value_is_int(apArg[0]) ){ - sxi32 iExitStatus; - /* Record exit status code */ - iExitStatus = jx9_value_to_int(apArg[0]); - pCtx->pVm->iExitStatus = iExitStatus; - } - } - /* Abort processing immediately */ - return JX9_ABORT; -} -/* - * Unset a memory object [i.e: a jx9_value]. - */ -JX9_PRIVATE sxi32 jx9VmUnsetMemObj(jx9_vm *pVm,sxu32 nObjIdx) -{ - jx9_value *pObj; - pObj = (jx9_value *)SySetAt(&pVm->aMemObj, nObjIdx); - if( pObj ){ - VmSlot sFree; - /* Release the object */ - jx9MemObjRelease(pObj); - /* Restore to the free list */ - sFree.nIdx = nObjIdx; - sFree.pUserData = 0; - SySetPut(&pVm->aFreeObj, (const void *)&sFree); - } - return SXRET_OK; -} -/* - * string gettype($var) - * Get the type of a variable - * Parameters - * $var - * The variable being type checked. - * Return - * String representation of the given variable type. - */ -static int vm_builtin_gettype(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zType = "null"; - if( nArg > 0 ){ - zType = jx9MemObjTypeDump(apArg[0]); - } - /* Return the variable type */ - jx9_result_string(pCtx, zType, -1/*Compute length automatically*/); - return SXRET_OK; -} -/* - * string get_resource_type(resource $handle) - * This function gets the type of the given resource. - * Parameters - * $handle - * The evaluated resource handle. - * Return - * If the given handle is a resource, this function will return a string - * representing its type. If the type is not identified by this function - * the return value will be the string Unknown. - * This function will return FALSE and generate an error if handle - * is not a resource. - */ -static int vm_builtin_get_resource_type(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - if( nArg < 1 || !jx9_value_is_resource(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE*/ - jx9_result_bool(pCtx, 0); - return SXRET_OK; - } - jx9_result_string_format(pCtx, "resID_%#x", apArg[0]->x.pOther); - return SXRET_OK; -} -/* - * void dump(expression, ....) - * dump — Dumps information about a variable - * Parameters - * One or more expression to dump. - * Returns - * Nothing. - */ -static int vm_builtin_dump(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyBlob sDump; /* Generated dump is stored here */ - int i; - SyBlobInit(&sDump,&pCtx->pVm->sAllocator); - /* Dump one or more expressions */ - for( i = 0 ; i < nArg ; i++ ){ - jx9_value *pObj = apArg[i]; - /* Reset the working buffer */ - SyBlobReset(&sDump); - /* Dump the given expression */ - jx9MemObjDump(&sDump,pObj); - /* Output */ - if( SyBlobLength(&sDump) > 0 ){ - jx9_context_output(pCtx, (const char *)SyBlobData(&sDump), (int)SyBlobLength(&sDump)); - } - } - /* Release the working buffer */ - SyBlobRelease(&sDump); - return SXRET_OK; -} -/* - * Section: - * Version, Credits and Copyright related functions. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Stable. - */ -/* - * string jx9_version(void) - * string jx9_credits(void) - * Returns the running version of the jx9 version. - * Parameters - * None - * Return - * Current jx9 version. - */ -static int vm_builtin_jx9_version(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SXUNUSED(nArg); - SXUNUSED(apArg); /* cc warning */ - /* Current engine version, signature and cipyright notice */ - jx9_result_string_format(pCtx,"%s %s, %s",JX9_VERSION,JX9_SIG,JX9_COPYRIGHT); - return JX9_OK; -} -/* - * Section: - * URL related routines. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* Forward declaration */ -static sxi32 VmHttpSplitURI(SyhttpUri *pOut, const char *zUri, sxu32 nLen); -/* - * value parse_url(string $url [, int $component = -1 ]) - * Parse a URL and return its fields. - * Parameters - * $url - * The URL to parse. - * $component - * Specify one of JX9_URL_SCHEME, JX9_URL_HOST, JX9_URL_PORT, JX9_URL_USER - * JX9_URL_PASS, JX9_URL_PATH, JX9_URL_QUERY or JX9_URL_FRAGMENT to retrieve - * just a specific URL component as a string (except when JX9_URL_PORT is given - * in which case the return value will be an integer). - * Return - * If the component parameter is omitted, an associative array is returned. - * At least one element will be present within the array. Potential keys within - * this array are: - * scheme - e.g. http - * host - * port - * user - * pass - * path - * query - after the question mark ? - * fragment - after the hashmark # - * Note: - * FALSE is returned on failure. - * This function work with relative URL unlike the one shipped - * with the standard JX9 engine. - */ -static int vm_builtin_parse_url(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zStr; /* Input string */ - SyString *pComp; /* Pointer to the URI component */ - SyhttpUri sURI; /* Parse of the given URI */ - int nLen; - sxi32 rc; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract the given URI */ - zStr = jx9_value_to_string(apArg[0], &nLen); - if( nLen < 1 ){ - /* Nothing to process, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Get a parse */ - rc = VmHttpSplitURI(&sURI, zStr, (sxu32)nLen); - if( rc != SXRET_OK ){ - /* Malformed input, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( nArg > 1 ){ - int nComponent = jx9_value_to_int(apArg[1]); - /* Refer to constant.c for constants values */ - switch(nComponent){ - case 1: /* JX9_URL_SCHEME */ - pComp = &sURI.sScheme; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - } - break; - case 2: /* JX9_URL_HOST */ - pComp = &sURI.sHost; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - } - break; - case 3: /* JX9_URL_PORT */ - pComp = &sURI.sPort; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - int iPort = 0; - /* Cast the value to integer */ - SyStrToInt32(pComp->zString, pComp->nByte, (void *)&iPort, 0); - jx9_result_int(pCtx, iPort); - } - break; - case 4: /* JX9_URL_USER */ - pComp = &sURI.sUser; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - } - break; - case 5: /* JX9_URL_PASS */ - pComp = &sURI.sPass; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - } - break; - case 7: /* JX9_URL_QUERY */ - pComp = &sURI.sQuery; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - } - break; - case 8: /* JX9_URL_FRAGMENT */ - pComp = &sURI.sFragment; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - } - break; - case 6: /* JX9_URL_PATH */ - pComp = &sURI.sPath; - if( pComp->nByte < 1 ){ - /* No available value, return NULL */ - jx9_result_null(pCtx); - }else{ - jx9_result_string(pCtx, pComp->zString, (int)pComp->nByte); - } - break; - default: - /* No such entry, return NULL */ - jx9_result_null(pCtx); - break; - } - }else{ - jx9_value *pArray, *pValue; - /* Return an associative array */ - pArray = jx9_context_new_array(pCtx); /* Empty array */ - pValue = jx9_context_new_scalar(pCtx); /* Array value */ - if( pArray == 0 || pValue == 0 ){ - /* Out of memory */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "jx9 engine is running out of memory"); - /* Return false */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Fill the array */ - pComp = &sURI.sScheme; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - jx9_array_add_strkey_elem(pArray, "scheme", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - pComp = &sURI.sHost; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - jx9_array_add_strkey_elem(pArray, "host", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - pComp = &sURI.sPort; - if( pComp->nByte > 0 ){ - int iPort = 0;/* cc warning */ - /* Convert to integer */ - SyStrToInt32(pComp->zString, pComp->nByte, (void *)&iPort, 0); - jx9_value_int(pValue, iPort); - jx9_array_add_strkey_elem(pArray, "port", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - pComp = &sURI.sUser; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - jx9_array_add_strkey_elem(pArray, "user", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - pComp = &sURI.sPass; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - jx9_array_add_strkey_elem(pArray, "pass", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - pComp = &sURI.sPath; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - jx9_array_add_strkey_elem(pArray, "path", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - pComp = &sURI.sQuery; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - jx9_array_add_strkey_elem(pArray, "query", pValue); /* Will make it's own copy */ - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pValue); - pComp = &sURI.sFragment; - if( pComp->nByte > 0 ){ - jx9_value_string(pValue, pComp->zString, (int)pComp->nByte); - jx9_array_add_strkey_elem(pArray, "fragment", pValue); /* Will make it's own copy */ - } - /* Return the created array */ - jx9_result_value(pCtx, pArray); - /* NOTE: - * Don't worry about freeing 'pValue', everything will be released - * automatically as soon we return from this function. - */ - } - /* All done */ - return JX9_OK; -} -/* - * Section: - * Array related routines. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - * Note 2012-5-21 01:04:15: - * Array related functions that need access to the underlying - * virtual machine are implemented here rather than 'hashmap.c' - */ -/* - * The [extract()] function store it's state information in an instance - * of the following structure. - */ -typedef struct extract_aux_data extract_aux_data; -struct extract_aux_data -{ - jx9_vm *pVm; /* VM that own this instance */ - int iCount; /* Number of variables successfully imported */ - const char *zPrefix; /* Prefix name */ - int Prefixlen; /* Prefix length */ - int iFlags; /* Control flags */ - char zWorker[1024]; /* Working buffer */ -}; -/* Forward declaration */ -static int VmExtractCallback(jx9_value *pKey, jx9_value *pValue, void *pUserData); -/* - * int extract(array $var_array[, int $extract_type = EXTR_OVERWRITE[, string $prefix = NULL ]]) - * Import variables into the current symbol table from an array. - * Parameters - * $var_array - * An associative array. This function treats keys as variable names and values - * as variable values. For each key/value pair it will create a variable in the current symbol - * table, subject to extract_type and prefix parameters. - * You must use an associative array; a numerically indexed array will not produce results - * unless you use EXTR_PREFIX_ALL or EXTR_PREFIX_INVALID. - * $extract_type - * The way invalid/numeric keys and collisions are treated is determined by the extract_type. - * It can be one of the following values: - * EXTR_OVERWRITE - * If there is a collision, overwrite the existing variable. - * EXTR_SKIP - * If there is a collision, don't overwrite the existing variable. - * EXTR_PREFIX_SAME - * If there is a collision, prefix the variable name with prefix. - * EXTR_PREFIX_ALL - * Prefix all variable names with prefix. - * EXTR_PREFIX_INVALID - * Only prefix invalid/numeric variable names with prefix. - * EXTR_IF_EXISTS - * Only overwrite the variable if it already exists in the current symbol table - * otherwise do nothing. - * This is useful for defining a list of valid variables and then extracting only those - * variables you have defined out of $_REQUEST, for example. - * EXTR_PREFIX_IF_EXISTS - * Only create prefixed variable names if the non-prefixed version of the same variable exists in - * the current symbol table. - * $prefix - * Note that prefix is only required if extract_type is EXTR_PREFIX_SAME, EXTR_PREFIX_ALL - * EXTR_PREFIX_INVALID or EXTR_PREFIX_IF_EXISTS. If the prefixed result is not a valid variable name - * it is not imported into the symbol table. Prefixes are automatically separated from the array key by an - * underscore character. - * Return - * Returns the number of variables successfully imported into the symbol table. - */ -static int vm_builtin_extract(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - extract_aux_data sAux; - jx9_hashmap *pMap; - if( nArg < 1 || !jx9_value_is_json_array(apArg[0]) ){ - /* Missing/Invalid arguments, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Point to the target hashmap */ - pMap = (jx9_hashmap *)apArg[0]->x.pOther; - if( pMap->nEntry < 1 ){ - /* Empty map, return 0 */ - jx9_result_int(pCtx, 0); - return JX9_OK; - } - /* Prepare the aux data */ - SyZero(&sAux, sizeof(extract_aux_data)-sizeof(sAux.zWorker)); - if( nArg > 1 ){ - sAux.iFlags = jx9_value_to_int(apArg[1]); - if( nArg > 2 ){ - sAux.zPrefix = jx9_value_to_string(apArg[2], &sAux.Prefixlen); - } - } - sAux.pVm = pCtx->pVm; - /* Invoke the worker callback */ - jx9HashmapWalk(pMap, VmExtractCallback, &sAux); - /* Number of variables successfully imported */ - jx9_result_int(pCtx, sAux.iCount); - return JX9_OK; -} -/* - * Worker callback for the [extract()] function defined - * below. - */ -static int VmExtractCallback(jx9_value *pKey, jx9_value *pValue, void *pUserData) -{ - extract_aux_data *pAux = (extract_aux_data *)pUserData; - int iFlags = pAux->iFlags; - jx9_vm *pVm = pAux->pVm; - jx9_value *pObj; - SyString sVar; - if( (iFlags & 0x10/* EXTR_PREFIX_INVALID */) && (pKey->iFlags & (MEMOBJ_INT|MEMOBJ_BOOL|MEMOBJ_REAL))){ - iFlags |= 0x08; /*EXTR_PREFIX_ALL*/ - } - /* Perform a string cast */ - jx9MemObjToString(pKey); - if( SyBlobLength(&pKey->sBlob) < 1 ){ - /* Unavailable variable name */ - return SXRET_OK; - } - sVar.nByte = 0; /* cc warning */ - if( (iFlags & 0x08/*EXTR_PREFIX_ALL*/ ) && pAux->Prefixlen > 0 ){ - sVar.nByte = (sxu32)SyBufferFormat(pAux->zWorker, sizeof(pAux->zWorker), "%.*s_%.*s", - pAux->Prefixlen, pAux->zPrefix, - SyBlobLength(&pKey->sBlob), SyBlobData(&pKey->sBlob) - ); - }else{ - sVar.nByte = (sxu32) SyMemcpy(SyBlobData(&pKey->sBlob), pAux->zWorker, - SXMIN(SyBlobLength(&pKey->sBlob), sizeof(pAux->zWorker))); - } - sVar.zString = pAux->zWorker; - /* Try to extract the variable */ - pObj = VmExtractMemObj(pVm, &sVar, TRUE, FALSE); - if( pObj ){ - /* Collision */ - if( iFlags & 0x02 /* EXTR_SKIP */ ){ - return SXRET_OK; - } - if( iFlags & 0x04 /* EXTR_PREFIX_SAME */ ){ - if( (iFlags & 0x08/*EXTR_PREFIX_ALL*/) || pAux->Prefixlen < 1){ - /* Already prefixed */ - return SXRET_OK; - } - sVar.nByte = SyBufferFormat( - pAux->zWorker, sizeof(pAux->zWorker), - "%.*s_%.*s", - pAux->Prefixlen, pAux->zPrefix, - SyBlobLength(&pKey->sBlob), SyBlobData(&pKey->sBlob) - ); - pObj = VmExtractMemObj(pVm, &sVar, TRUE, TRUE); - } - }else{ - /* Create the variable */ - pObj = VmExtractMemObj(pVm, &sVar, TRUE, TRUE); - } - if( pObj ){ - /* Overwrite the old value */ - jx9MemObjStore(pValue, pObj); - /* Increment counter */ - pAux->iCount++; - } - return SXRET_OK; -} -/* - * Compile and evaluate a JX9 chunk at run-time. - * Refer to the include language construct implementation for more - * information. - */ -static sxi32 VmEvalChunk( - jx9_vm *pVm, /* Underlying Virtual Machine */ - jx9_context *pCtx, /* Call Context */ - SyString *pChunk, /* JX9 chunk to evaluate */ - int iFlags, /* Compile flag */ - int bTrueReturn /* TRUE to return execution result */ - ) -{ - SySet *pByteCode, aByteCode; - ProcConsumer xErr = 0; - void *pErrData = 0; - /* Initialize bytecode container */ - SySetInit(&aByteCode, &pVm->sAllocator, sizeof(VmInstr)); - SySetAlloc(&aByteCode, 0x20); - /* Reset the code generator */ - if( bTrueReturn ){ - /* Included file, log compile-time errors */ - xErr = pVm->pEngine->xConf.xErr; - pErrData = pVm->pEngine->xConf.pErrData; - } - jx9ResetCodeGenerator(pVm, xErr, pErrData); - /* Swap bytecode container */ - pByteCode = pVm->pByteContainer; - pVm->pByteContainer = &aByteCode; - /* Compile the chunk */ - jx9CompileScript(pVm, pChunk, iFlags); - if( pVm->sCodeGen.nErr > 0 ){ - /* Compilation error, return false */ - if( pCtx ){ - jx9_result_bool(pCtx, 0); - } - }else{ - jx9_value sResult; /* Return value */ - if( SXRET_OK != jx9VmEmitInstr(pVm, JX9_OP_DONE, 0, 0, 0, 0) ){ - /* Out of memory */ - if( pCtx ){ - jx9_result_bool(pCtx, 0); - } - goto Cleanup; - } - if( bTrueReturn ){ - /* Assume a boolean true return value */ - jx9MemObjInitFromBool(pVm, &sResult, 1); - }else{ - /* Assume a null return value */ - jx9MemObjInit(pVm, &sResult); - } - /* Execute the compiled chunk */ - VmLocalExec(pVm, &aByteCode, &sResult); - if( pCtx ){ - /* Set the execution result */ - jx9_result_value(pCtx, &sResult); - } - jx9MemObjRelease(&sResult); - } -Cleanup: - /* Cleanup the mess left behind */ - pVm->pByteContainer = pByteCode; - SySetRelease(&aByteCode); - return SXRET_OK; -} -/* - * Check if a file path is already included. - */ -static int VmIsIncludedFile(jx9_vm *pVm, SyString *pFile) -{ - SyString *aEntries; - sxu32 n; - aEntries = (SyString *)SySetBasePtr(&pVm->aIncluded); - /* Perform a linear search */ - for( n = 0 ; n < SySetUsed(&pVm->aIncluded) ; ++n ){ - if( SyStringCmp(pFile, &aEntries[n], SyMemcmp) == 0 ){ - /* Already included */ - return TRUE; - } - } - return FALSE; -} -/* - * Push a file path in the appropriate VM container. - */ -JX9_PRIVATE sxi32 jx9VmPushFilePath(jx9_vm *pVm, const char *zPath, int nLen, sxu8 bMain, sxi32 *pNew) -{ - SyString sPath; - char *zDup; -#ifdef __WINNT__ - char *zCur; -#endif - sxi32 rc; - if( nLen < 0 ){ - nLen = SyStrlen(zPath); - } - /* Duplicate the file path first */ - zDup = SyMemBackendStrDup(&pVm->sAllocator, zPath, nLen); - if( zDup == 0 ){ - return SXERR_MEM; - } -#ifdef __WINNT__ - /* Normalize path on windows - * Example: - * Path/To/File.jx9 - * becomes - * path\to\file.jx9 - */ - zCur = zDup; - while( zCur[0] != 0 ){ - if( zCur[0] == '/' ){ - zCur[0] = '\\'; - }else if( (unsigned char)zCur[0] < 0xc0 && SyisUpper(zCur[0]) ){ - int c = SyToLower(zCur[0]); - zCur[0] = (char)c; /* MSVC stupidity */ - } - zCur++; - } -#endif - /* Install the file path */ - SyStringInitFromBuf(&sPath, zDup, nLen); - if( !bMain ){ - if( VmIsIncludedFile(&(*pVm), &sPath) ){ - /* Already included */ - *pNew = 0; - }else{ - /* Insert in the corresponding container */ - rc = SySetPut(&pVm->aIncluded, (const void *)&sPath); - if( rc != SXRET_OK ){ - SyMemBackendFree(&pVm->sAllocator, zDup); - return rc; - } - *pNew = 1; - } - } - SySetPut(&pVm->aFiles, (const void *)&sPath); - return SXRET_OK; -} -/* - * Compile and Execute a JX9 script at run-time. - * SXRET_OK is returned on sucessful evaluation.Any other return values - * indicates failure. - * Note that the JX9 script to evaluate can be a local or remote file.In - * either cases the [jx9StreamReadWholeFile()] function handle all the underlying - * operations. - * If the [jJX9_DISABLE_BUILTIN_FUNC] compile-time directive is defined, then - * this function is a no-op. - * Refer to the implementation of the include(), import() language - * constructs for more information. - */ -static sxi32 VmExecIncludedFile( - jx9_context *pCtx, /* Call Context */ - SyString *pPath, /* Script path or URL*/ - int IncludeOnce /* TRUE if called from import() or require_once() */ - ) -{ - sxi32 rc; -#ifndef JX9_DISABLE_BUILTIN_FUNC - const jx9_io_stream *pStream; - SyBlob sContents; - void *pHandle; - jx9_vm *pVm; - int isNew; - /* Initialize fields */ - pVm = pCtx->pVm; - SyBlobInit(&sContents, &pVm->sAllocator); - isNew = 0; - /* Extract the associated stream */ - pStream = jx9VmGetStreamDevice(pVm, &pPath->zString, pPath->nByte); - /* - * Open the file or the URL [i.e: http://jx9.symisc.net/example/hello.jx9.txt"] - * in a read-only mode. - */ - pHandle = jx9StreamOpenHandle(pVm, pStream,pPath->zString, JX9_IO_OPEN_RDONLY, TRUE, 0, TRUE, &isNew); - if( pHandle == 0 ){ - return SXERR_IO; - } - rc = SXRET_OK; /* Stupid cc warning */ - if( IncludeOnce && !isNew ){ - /* Already included */ - rc = SXERR_EXISTS; - }else{ - /* Read the whole file contents */ - rc = jx9StreamReadWholeFile(pHandle, pStream, &sContents); - if( rc == SXRET_OK ){ - SyString sScript; - /* Compile and execute the script */ - SyStringInitFromBuf(&sScript, SyBlobData(&sContents), SyBlobLength(&sContents)); - VmEvalChunk(pCtx->pVm, &(*pCtx), &sScript, 0, TRUE); - } - } - /* Pop from the set of included file */ - (void)SySetPop(&pVm->aFiles); - /* Close the handle */ - jx9StreamCloseHandle(pStream, pHandle); - /* Release the working buffer */ - SyBlobRelease(&sContents); -#else - pCtx = 0; /* cc warning */ - pPath = 0; - IncludeOnce = 0; - rc = SXERR_IO; -#endif /* JX9_DISABLE_BUILTIN_FUNC */ - return rc; -} -/* * include: - * According to the JX9 reference manual. - * The include() function includes and evaluates the specified file. - * Files are included based on the file path given or, if none is given - * the include_path specified.If the file isn't found in the include_path - * include() will finally check in the calling script's own directory - * and the current working directory before failing. The include() - * construct will emit a warning if it cannot find a file; this is different - * behavior from require(), which will emit a fatal error. - * If a path is defined — whether absolute (starting with a drive letter - * or \ on Windows, or / on Unix/Linux systems) or relative to the current - * directory (starting with . or ..) — the include_path will be ignored altogether. - * For example, if a filename begins with ../, the parser will look in the parent - * directory to find the requested file. - * When a file is included, the code it contains inherits the variable scope - * of the line on which the include occurs. Any variables available at that line - * in the calling file will be available within the called file, from that point forward. - * However, all functions and objectes defined in the included file have the global scope. - */ -static int vm_builtin_include(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyString sFile; - sxi32 rc; - if( nArg < 1 ){ - /* Nothing to evaluate, return NULL */ - jx9_result_null(pCtx); - return SXRET_OK; - } - /* File to include */ - sFile.zString = jx9_value_to_string(apArg[0], (int *)&sFile.nByte); - if( sFile.nByte < 1 ){ - /* Empty string, return NULL */ - jx9_result_null(pCtx); - return SXRET_OK; - } - /* Open, compile and execute the desired script */ - rc = VmExecIncludedFile(&(*pCtx), &sFile, FALSE); - if( rc != SXRET_OK ){ - /* Emit a warning and return false */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, "IO error while importing: '%z'", &sFile); - jx9_result_bool(pCtx, 0); - } - return SXRET_OK; -} -/* - * import: - * According to the JX9 reference manual. - * The import() statement includes and evaluates the specified file during - * the execution of the script. This is a behavior similar to the include() - * statement, with the only difference being that if the code from a file has already - * been included, it will not be included again. As the name suggests, it will be included - * just once. - */ -static int vm_builtin_import(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - SyString sFile; - sxi32 rc; - if( nArg < 1 ){ - /* Nothing to evaluate, return NULL */ - jx9_result_null(pCtx); - return SXRET_OK; - } - /* File to include */ - sFile.zString = jx9_value_to_string(apArg[0], (int *)&sFile.nByte); - if( sFile.nByte < 1 ){ - /* Empty string, return NULL */ - jx9_result_null(pCtx); - return SXRET_OK; - } - /* Open, compile and execute the desired script */ - rc = VmExecIncludedFile(&(*pCtx), &sFile, TRUE); - if( rc == SXERR_EXISTS ){ - /* File already included, return TRUE */ - jx9_result_bool(pCtx, 1); - return SXRET_OK; - } - if( rc != SXRET_OK ){ - /* Emit a warning and return false */ - jx9_context_throw_error_format(pCtx, JX9_CTX_WARNING, "IO error while importing: '%z'", &sFile); - jx9_result_bool(pCtx, 0); - } - return SXRET_OK; -} -/* - * Section: - * Command line arguments processing. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ -/* - * Check if a short option argument [i.e: -c] is available in the command - * line string. Return a pointer to the start of the stream on success. - * NULL otherwise. - */ -static const char * VmFindShortOpt(int c, const char *zIn, const char *zEnd) -{ - while( zIn < zEnd ){ - if( zIn[0] == '-' && &zIn[1] < zEnd && (int)zIn[1] == c ){ - /* Got one */ - return &zIn[1]; - } - /* Advance the cursor */ - zIn++; - } - /* No such option */ - return 0; -} -/* - * Check if a long option argument [i.e: --opt] is available in the command - * line string. Return a pointer to the start of the stream on success. - * NULL otherwise. - */ -static const char * VmFindLongOpt(const char *zLong, int nByte, const char *zIn, const char *zEnd) -{ - const char *zOpt; - while( zIn < zEnd ){ - if( zIn[0] == '-' && &zIn[1] < zEnd && (int)zIn[1] == '-' ){ - zIn += 2; - zOpt = zIn; - while( zIn < zEnd && !SyisSpace(zIn[0]) ){ - if( zIn[0] == '=' /* --opt=val */){ - break; - } - zIn++; - } - /* Test */ - if( (int)(zIn-zOpt) == nByte && SyMemcmp(zOpt, zLong, nByte) == 0 ){ - /* Got one, return it's value */ - return zIn; - } - - }else{ - zIn++; - } - } - /* No such option */ - return 0; -} -/* - * Long option [i.e: --opt] arguments private data structure. - */ -struct getopt_long_opt -{ - const char *zArgIn, *zArgEnd; /* Command line arguments */ - jx9_value *pWorker; /* Worker variable*/ - jx9_value *pArray; /* getopt() return value */ - jx9_context *pCtx; /* Call Context */ -}; -/* Forward declaration */ -static int VmProcessLongOpt(jx9_value *pKey, jx9_value *pValue, void *pUserData); -/* - * Extract short or long argument option values. - */ -static void VmExtractOptArgValue( - jx9_value *pArray, /* getopt() return value */ - jx9_value *pWorker, /* Worker variable */ - const char *zArg, /* Argument stream */ - const char *zArgEnd, /* End of the argument stream */ - int need_val, /* TRUE to fetch option argument */ - jx9_context *pCtx, /* Call Context */ - const char *zName /* Option name */) -{ - jx9_value_bool(pWorker, 0); - if( !need_val ){ - /* - * Option does not need arguments. - * Insert the option name and a boolean FALSE. - */ - jx9_array_add_strkey_elem(pArray, (const char *)zName, pWorker); /* Will make it's own copy */ - }else{ - const char *zCur; - /* Extract option argument */ - zArg++; - if( zArg < zArgEnd && zArg[0] == '=' ){ - zArg++; - } - while( zArg < zArgEnd && (unsigned char)zArg[0] < 0xc0 && SyisSpace(zArg[0]) ){ - zArg++; - } - if( zArg >= zArgEnd || zArg[0] == '-' ){ - /* - * Argument not found. - * Insert the option name and a boolean FALSE. - */ - jx9_array_add_strkey_elem(pArray, (const char *)zName, pWorker); /* Will make it's own copy */ - return; - } - /* Delimit the value */ - zCur = zArg; - if( zArg[0] == '\'' || zArg[0] == '"' ){ - int d = zArg[0]; - /* Delimt the argument */ - zArg++; - zCur = zArg; - while( zArg < zArgEnd ){ - if( zArg[0] == d && zArg[-1] != '\\' ){ - /* Delimiter found, exit the loop */ - break; - } - zArg++; - } - /* Save the value */ - jx9_value_string(pWorker, zCur, (int)(zArg-zCur)); - if( zArg < zArgEnd ){ zArg++; } - }else{ - while( zArg < zArgEnd && !SyisSpace(zArg[0]) ){ - zArg++; - } - /* Save the value */ - jx9_value_string(pWorker, zCur, (int)(zArg-zCur)); - } - /* - * Check if we are dealing with multiple values. - * If so, create an array to hold them, rather than a scalar variable. - */ - while( zArg < zArgEnd && (unsigned char)zArg[0] < 0xc0 && SyisSpace(zArg[0]) ){ - zArg++; - } - if( zArg < zArgEnd && zArg[0] != '-' ){ - jx9_value *pOptArg; /* Array of option arguments */ - pOptArg = jx9_context_new_array(pCtx); - if( pOptArg == 0 ){ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "JX9 is running out of memory"); - }else{ - /* Insert the first value */ - jx9_array_add_elem(pOptArg, 0, pWorker); /* Will make it's own copy */ - for(;;){ - if( zArg >= zArgEnd || zArg[0] == '-' ){ - /* No more value */ - break; - } - /* Delimit the value */ - zCur = zArg; - if( zArg < zArgEnd && zArg[0] == '\\' ){ - zArg++; - zCur = zArg; - } - while( zArg < zArgEnd && !SyisSpace(zArg[0]) ){ - zArg++; - } - /* Reset the string cursor */ - jx9_value_reset_string_cursor(pWorker); - /* Save the value */ - jx9_value_string(pWorker, zCur, (int)(zArg-zCur)); - /* Insert */ - jx9_array_add_elem(pOptArg, 0, pWorker); /* Will make it's own copy */ - /* Jump trailing white spaces */ - while( zArg < zArgEnd && (unsigned char)zArg[0] < 0xc0 && SyisSpace(zArg[0]) ){ - zArg++; - } - } - /* Insert the option arg array */ - jx9_array_add_strkey_elem(pArray, (const char *)zName, pOptArg); /* Will make it's own copy */ - /* Safely release */ - jx9_context_release_value(pCtx, pOptArg); - } - }else{ - /* Single value */ - jx9_array_add_strkey_elem(pArray, (const char *)zName, pWorker); /* Will make it's own copy */ - } - } -} -/* - * array getopt(string $options[, array $longopts ]) - * Gets options from the command line argument list. - * Parameters - * $options - * Each character in this string will be used as option characters - * and matched against options passed to the script starting with - * a single hyphen (-). For example, an option string "x" recognizes - * an option -x. Only a-z, A-Z and 0-9 are allowed. - * $longopts - * An array of options. Each element in this array will be used as option - * strings and matched against options passed to the script starting with - * two hyphens (--). For example, an longopts element "opt" recognizes an - * option --opt. - * Return - * This function will return an array of option / argument pairs or FALSE - * on failure. - */ -static int vm_builtin_getopt(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zIn, *zEnd, *zArg, *zArgIn, *zArgEnd; - struct getopt_long_opt sLong; - jx9_value *pArray, *pWorker; - SyBlob *pArg; - int nByte; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return FALSE */ - jx9_context_throw_error(pCtx, JX9_CTX_ERR, "Missing/Invalid option arguments"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Extract option arguments */ - zIn = jx9_value_to_string(apArg[0], &nByte); - zEnd = &zIn[nByte]; - /* Point to the string representation of the $argv[] array */ - pArg = &pCtx->pVm->sArgv; - /* Create a new empty array and a worker variable */ - pArray = jx9_context_new_array(pCtx); - pWorker = jx9_context_new_scalar(pCtx); - if( pArray == 0 || pWorker == 0 ){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR, "JX9 is running out of memory"); - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - if( SyBlobLength(pArg) < 1 ){ - /* Empty command line, return the empty array*/ - jx9_result_value(pCtx, pArray); - /* Everything will be released automatically when we return - * from this function. - */ - return JX9_OK; - } - zArgIn = (const char *)SyBlobData(pArg); - zArgEnd = &zArgIn[SyBlobLength(pArg)]; - /* Fill the long option structure */ - sLong.pArray = pArray; - sLong.pWorker = pWorker; - sLong.zArgIn = zArgIn; - sLong.zArgEnd = zArgEnd; - sLong.pCtx = pCtx; - /* Start processing */ - while( zIn < zEnd ){ - int c = zIn[0]; - int need_val = 0; - /* Advance the stream cursor */ - zIn++; - /* Ignore non-alphanum characters */ - if( !SyisAlphaNum(c) ){ - continue; - } - if( zIn < zEnd && zIn[0] == ':' ){ - zIn++; - need_val = 1; - if( zIn < zEnd && zIn[0] == ':' ){ - zIn++; - } - } - /* Find option */ - zArg = VmFindShortOpt(c, zArgIn, zArgEnd); - if( zArg == 0 ){ - /* No such option */ - continue; - } - /* Extract option argument value */ - VmExtractOptArgValue(pArray, pWorker, zArg, zArgEnd, need_val, pCtx, (const char *)&c); - } - if( nArg > 1 && jx9_value_is_json_array(apArg[1]) && jx9_array_count(apArg[1]) > 0 ){ - /* Process long options */ - jx9_array_walk(apArg[1], VmProcessLongOpt, &sLong); - } - /* Return the option array */ - jx9_result_value(pCtx, pArray); - /* - * Don't worry about freeing memory, everything will be released - * automatically as soon we return from this foreign function. - */ - return JX9_OK; -} -/* - * Array walker callback used for processing long options values. - */ -static int VmProcessLongOpt(jx9_value *pKey, jx9_value *pValue, void *pUserData) -{ - struct getopt_long_opt *pOpt = (struct getopt_long_opt *)pUserData; - const char *zArg, *zOpt, *zEnd; - int need_value = 0; - int nByte; - /* Value must be of type string */ - if( !jx9_value_is_string(pValue) ){ - /* Simply ignore */ - return JX9_OK; - } - zOpt = jx9_value_to_string(pValue, &nByte); - if( nByte < 1 ){ - /* Empty string, ignore */ - return JX9_OK; - } - zEnd = &zOpt[nByte - 1]; - if( zEnd[0] == ':' ){ - char *zTerm; - /* Try to extract a value */ - need_value = 1; - while( zEnd >= zOpt && zEnd[0] == ':' ){ - zEnd--; - } - if( zOpt >= zEnd ){ - /* Empty string, ignore */ - SXUNUSED(pKey); - return JX9_OK; - } - zEnd++; - zTerm = (char *)zEnd; - zTerm[0] = 0; - }else{ - zEnd = &zOpt[nByte]; - } - /* Find the option */ - zArg = VmFindLongOpt(zOpt, (int)(zEnd-zOpt), pOpt->zArgIn, pOpt->zArgEnd); - if( zArg == 0 ){ - /* No such option, return immediately */ - return JX9_OK; - } - /* Try to extract a value */ - VmExtractOptArgValue(pOpt->pArray, pOpt->pWorker, zArg, pOpt->zArgEnd, need_value, pOpt->pCtx, zOpt); - return JX9_OK; -} -/* - * int utf8_encode(string $input) - * UTF-8 encoding. - * This function encodes the string data to UTF-8, and returns the encoded version. - * UTF-8 is a standard mechanism used by Unicode for encoding wide character values - * into a byte stream. UTF-8 is transparent to plain ASCII characters, is self-synchronized - * (meaning it is possible for a program to figure out where in the bytestream characters start) - * and can be used with normal string comparison functions for sorting and such. - * Notes on UTF-8 (According to SQLite3 authors): - * Byte-0 Byte-1 Byte-2 Byte-3 Value - * 0xxxxxxx 00000000 00000000 0xxxxxxx - * 110yyyyy 10xxxxxx 00000000 00000yyy yyxxxxxx - * 1110zzzz 10yyyyyy 10xxxxxx 00000000 zzzzyyyy yyxxxxxx - * 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx 000uuuuu zzzzyyyy yyxxxxxx - * Parameters - * $input - * String to encode or NULL on failure. - * Return - * An UTF-8 encoded string. - */ -static int vm_builtin_utf8_encode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nByte, c, e; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nByte); - if( nByte < 1 ){ - /* Empty string, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - zEnd = &zIn[nByte]; - /* Start the encoding process */ - for(;;){ - if( zIn >= zEnd ){ - /* End of input */ - break; - } - c = zIn[0]; - /* Advance the stream cursor */ - zIn++; - /* Encode */ - if( c<0x00080 ){ - e = (c&0xFF); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - }else if( c<0x00800 ){ - e = 0xC0 + ((c>>6)&0x1F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - e = 0x80 + (c & 0x3F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - }else if( c<0x10000 ){ - e = 0xE0 + ((c>>12)&0x0F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - e = 0x80 + ((c>>6) & 0x3F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - e = 0x80 + (c & 0x3F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - }else{ - e = 0xF0 + ((c>>18) & 0x07); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - e = 0x80 + ((c>>12) & 0x3F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - e = 0x80 + ((c>>6) & 0x3F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - e = 0x80 + (c & 0x3F); - jx9_result_string(pCtx, (const char *)&e, (int)sizeof(char)); - } - } - /* All done */ - return JX9_OK; -} -/* - * UTF-8 decoding routine extracted from the sqlite3 source tree. - * Original author: D. Richard Hipp (http://www.sqlite.org) - * Status: Public Domain - */ -/* -** This lookup table is used to help decode the first byte of -** a multi-byte UTF8 character. -*/ -static const unsigned char UtfTrans1[] = { - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x00, 0x01, 0x02, 0x03, 0x00, 0x01, 0x00, 0x00, -}; -/* -** Translate a single UTF-8 character. Return the unicode value. -** -** During translation, assume that the byte that zTerm points -** is a 0x00. -** -** Write a pointer to the next unread byte back into *pzNext. -** -** Notes On Invalid UTF-8: -** -** * This routine never allows a 7-bit character (0x00 through 0x7f) to -** be encoded as a multi-byte character. Any multi-byte character that -** attempts to encode a value between 0x00 and 0x7f is rendered as 0xfffd. -** -** * This routine never allows a UTF16 surrogate value to be encoded. -** If a multi-byte character attempts to encode a value between -** 0xd800 and 0xe000 then it is rendered as 0xfffd. -** -** * Bytes in the range of 0x80 through 0xbf which occur as the first -** byte of a character are interpreted as single-byte characters -** and rendered as themselves even though they are technically -** invalid characters. -** -** * This routine accepts an infinite number of different UTF8 encodings -** for unicode values 0x80 and greater. It do not change over-length -** encodings to 0xfffd as some systems recommend. -*/ -#define READ_UTF8(zIn, zTerm, c) \ - c = *(zIn++); \ - if( c>=0xc0 ){ \ - c = UtfTrans1[c-0xc0]; \ - while( zIn!=zTerm && (*zIn & 0xc0)==0x80 ){ \ - c = (c<<6) + (0x3f & *(zIn++)); \ - } \ - if( c<0x80 \ - || (c&0xFFFFF800)==0xD800 \ - || (c&0xFFFFFFFE)==0xFFFE ){ c = 0xFFFD; } \ - } -JX9_PRIVATE int jx9Utf8Read( - const unsigned char *z, /* First byte of UTF-8 character */ - const unsigned char *zTerm, /* Pretend this byte is 0x00 */ - const unsigned char **pzNext /* Write first byte past UTF-8 char here */ -){ - int c; - READ_UTF8(z, zTerm, c); - *pzNext = z; - return c; -} -/* - * string utf8_decode(string $data) - * This function decodes data, assumed to be UTF-8 encoded, to unicode. - * Parameters - * data - * An UTF-8 encoded string. - * Return - * Unicode decoded string or NULL on failure. - */ -static int vm_builtin_utf8_decode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const unsigned char *zIn, *zEnd; - int nByte, c; - if( nArg < 1 ){ - /* Missing arguments, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the target string */ - zIn = (const unsigned char *)jx9_value_to_string(apArg[0], &nByte); - if( nByte < 1 ){ - /* Empty string, return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - zEnd = &zIn[nByte]; - /* Start the decoding process */ - while( zIn < zEnd ){ - c = jx9Utf8Read(zIn, zEnd, &zIn); - if( c == 0x0 ){ - break; - } - jx9_result_string(pCtx, (const char *)&c, (int)sizeof(char)); - } - return JX9_OK; -} -/* - * string json_encode(mixed $value) - * Returns a string containing the JSON representation of value. - * Parameters - * $value - * The value being encoded. Can be any type except a resource. - * Return - * Returns a JSON encoded string on success. FALSE otherwise - */ -static int vm_builtin_json_encode(jx9_context *pCtx,int nArg,jx9_value **apArg) -{ - SyBlob sBlob; - if( nArg < 1 ){ - /* Missing arguments, return FALSE */ - jx9_result_bool(pCtx, 0); - return JX9_OK; - } - /* Init the working buffer */ - SyBlobInit(&sBlob,&pCtx->pVm->sAllocator); - /* Perform the encoding operation */ - jx9JsonSerialize(apArg[0],&sBlob); - /* Return the serialized value */ - jx9_result_string(pCtx,(const char *)SyBlobData(&sBlob),(int)SyBlobLength(&sBlob)); - /* Cleanup */ - SyBlobRelease(&sBlob); - /* All done */ - return JX9_OK; -} -/* - * mixed json_decode(string $json) - * Takes a JSON encoded string and converts it into a JX9 variable. - * Parameters - * $json - * The json string being decoded. - * Return - * The value encoded in json in appropriate JX9 type. Values true, false and null (case-insensitive) - * are returned as TRUE, FALSE and NULL respectively. NULL is returned if the json cannot be decoded - * or if the encoded data is deeper than the recursion limit. - */ -static int vm_builtin_json_decode(jx9_context *pCtx, int nArg, jx9_value **apArg) -{ - const char *zJSON; - int nByte; - if( nArg < 1 || !jx9_value_is_string(apArg[0]) ){ - /* Missing/Invalid arguments, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the JSON string */ - zJSON = jx9_value_to_string(apArg[0], &nByte); - if( nByte < 1 ){ - /* Empty string, return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Decode the raw JSON */ - jx9JsonDecode(pCtx,zJSON,nByte); - return JX9_OK; -} -/* Table of built-in VM functions. */ -static const jx9_builtin_func aVmFunc[] = { - /* JSON Encoding/Decoding */ - { "json_encode", vm_builtin_json_encode }, - { "json_decode", vm_builtin_json_decode }, - /* Functions calls */ - { "func_num_args" , vm_builtin_func_num_args }, - { "func_get_arg" , vm_builtin_func_get_arg }, - { "func_get_args" , vm_builtin_func_get_args }, - { "function_exists", vm_builtin_func_exists }, - { "is_callable" , vm_builtin_is_callable }, - { "get_defined_functions", vm_builtin_get_defined_func }, - /* Constants management */ - { "defined", vm_builtin_defined }, - { "get_defined_constants", vm_builtin_get_defined_constants }, - /* Random numbers/strings generators */ - { "rand", vm_builtin_rand }, - { "rand_str", vm_builtin_rand_str }, - { "getrandmax", vm_builtin_getrandmax }, - /* Language constructs functions */ - { "print", vm_builtin_print }, - { "exit", vm_builtin_exit }, - { "die", vm_builtin_exit }, - /* Variable handling functions */ - { "gettype", vm_builtin_gettype }, - { "get_resource_type", vm_builtin_get_resource_type}, - /* Variable dumping */ - { "dump", vm_builtin_dump }, - /* Release info */ - {"jx9_version", vm_builtin_jx9_version }, - {"jx9_credits", vm_builtin_jx9_version }, - {"jx9_info", vm_builtin_jx9_version }, - {"jx9_copyright", vm_builtin_jx9_version }, - /* hashmap */ - {"extract", vm_builtin_extract }, - /* URL related function */ - {"parse_url", vm_builtin_parse_url }, - /* UTF-8 encoding/decoding */ - {"utf8_encode", vm_builtin_utf8_encode}, - {"utf8_decode", vm_builtin_utf8_decode}, - /* Command line processing */ - {"getopt", vm_builtin_getopt }, - /* Files/URI inclusion facility */ - { "include", vm_builtin_include }, - { "import", vm_builtin_import } -}; -/* - * Register the built-in VM functions defined above. - */ -static sxi32 VmRegisterSpecialFunction(jx9_vm *pVm) -{ - sxi32 rc; - sxu32 n; - for( n = 0 ; n < SX_ARRAYSIZE(aVmFunc) ; ++n ){ - /* Note that these special functions have access - * to the underlying virtual machine as their - * private data. - */ - rc = jx9_create_function(&(*pVm), aVmFunc[n].zName, aVmFunc[n].xFunc, &(*pVm)); - if( rc != SXRET_OK ){ - return rc; - } - } - return SXRET_OK; -} -#ifndef JX9_DISABLE_BUILTIN_FUNC -/* - * Extract the IO stream device associated with a given scheme. - * Return a pointer to an instance of jx9_io_stream when the scheme - * have an associated IO stream registered with it. NULL otherwise. - * If no scheme:// is avalilable then the file:// scheme is assumed. - * For more information on how to register IO stream devices, please - * refer to the official documentation. - */ -JX9_PRIVATE const jx9_io_stream * jx9VmGetStreamDevice( - jx9_vm *pVm, /* Target VM */ - const char **pzDevice, /* Full path, URI, ... */ - int nByte /* *pzDevice length*/ - ) -{ - const char *zIn, *zEnd, *zCur, *zNext; - jx9_io_stream **apStream, *pStream; - SyString sDev, sCur; - sxu32 n, nEntry; - int rc; - /* Check if a scheme [i.e: file://, http://, zip://...] is available */ - zNext = zCur = zIn = *pzDevice; - zEnd = &zIn[nByte]; - while( zIn < zEnd ){ - if( zIn < &zEnd[-3]/*://*/ && zIn[0] == ':' && zIn[1] == '/' && zIn[2] == '/' ){ - /* Got one */ - zNext = &zIn[sizeof("://")-1]; - break; - } - /* Advance the cursor */ - zIn++; - } - if( zIn >= zEnd ){ - /* No such scheme, return the default stream */ - return pVm->pDefStream; - } - SyStringInitFromBuf(&sDev, zCur, zIn-zCur); - /* Remove leading and trailing white spaces */ - SyStringFullTrim(&sDev); - /* Perform a linear lookup on the installed stream devices */ - apStream = (jx9_io_stream **)SySetBasePtr(&pVm->aIOstream); - nEntry = SySetUsed(&pVm->aIOstream); - for( n = 0 ; n < nEntry ; n++ ){ - pStream = apStream[n]; - SyStringInitFromBuf(&sCur, pStream->zName, SyStrlen(pStream->zName)); - /* Perfrom a case-insensitive comparison */ - rc = SyStringCmp(&sDev, &sCur, SyStrnicmp); - if( rc == 0 ){ - /* Stream device found */ - *pzDevice = zNext; - return pStream; - } - } - /* No such stream, return NULL */ - return 0; -} -#endif /* JX9_DISABLE_BUILTIN_FUNC */ -/* - * Section: - * HTTP/URI related routines. - * Authors: - * Symisc Systems, devel@symisc.net. - * Copyright (C) Symisc Systems, http://jx9.symisc.net - * Status: - * Stable. - */ - /* - * URI Parser: Split an URI into components [i.e: Host, Path, Query, ...]. - * URI syntax: [method:/][/[user[:pwd]@]host[:port]/][document] - * This almost, but not quite, RFC1738 URI syntax. - * This routine is not a validator, it does not check for validity - * nor decode URI parts, the only thing this routine does is splitting - * the input to its fields. - * Upper layer are responsible of decoding and validating URI parts. - * On success, this function populate the "SyhttpUri" structure passed - * as the first argument. Otherwise SXERR_* is returned when a malformed - * input is encountered. - */ - static sxi32 VmHttpSplitURI(SyhttpUri *pOut, const char *zUri, sxu32 nLen) - { - const char *zEnd = &zUri[nLen]; - sxu8 bHostOnly = FALSE; - sxu8 bIPv6 = FALSE ; - const char *zCur; - SyString *pComp; - sxu32 nPos = 0; - sxi32 rc; - /* Zero the structure first */ - SyZero(pOut, sizeof(SyhttpUri)); - /* Remove leading and trailing white spaces */ - SyStringInitFromBuf(&pOut->sRaw, zUri, nLen); - SyStringFullTrim(&pOut->sRaw); - /* Find the first '/' separator */ - rc = SyByteFind(zUri, (sxu32)(zEnd - zUri), '/', &nPos); - if( rc != SXRET_OK ){ - /* Assume a host name only */ - zCur = zEnd; - bHostOnly = TRUE; - goto ProcessHost; - } - zCur = &zUri[nPos]; - if( zUri != zCur && zCur[-1] == ':' ){ - /* Extract a scheme: - * Not that we can get an invalid scheme here. - * Fortunately the caller can discard any URI by comparing this scheme with its - * registered schemes and will report the error as soon as his comparison function - * fail. - */ - pComp = &pOut->sScheme; - SyStringInitFromBuf(pComp, zUri, (sxu32)(zCur - zUri - 1)); - SyStringLeftTrim(pComp); - } - if( zCur[1] != '/' ){ - if( zCur == zUri || zCur[-1] == ':' ){ - /* No authority */ - goto PathSplit; - } - /* There is something here , we will assume its an authority - * and someone has forgot the two prefix slashes "//", - * sooner or later we will detect if we are dealing with a malicious - * user or not, but now assume we are dealing with an authority - * and let the caller handle all the validation process. - */ - goto ProcessHost; - } - zUri = &zCur[2]; - zCur = zEnd; - rc = SyByteFind(zUri, (sxu32)(zEnd - zUri), '/', &nPos); - if( rc == SXRET_OK ){ - zCur = &zUri[nPos]; - } - ProcessHost: - /* Extract user information if present */ - rc = SyByteFind(zUri, (sxu32)(zCur - zUri), '@', &nPos); - if( rc == SXRET_OK ){ - if( nPos > 0 ){ - sxu32 nPassOfft; /* Password offset */ - pComp = &pOut->sUser; - SyStringInitFromBuf(pComp, zUri, nPos); - /* Extract the password if available */ - rc = SyByteFind(zUri, (sxu32)(zCur - zUri), ':', &nPassOfft); - if( rc == SXRET_OK && nPassOfft < nPos){ - pComp->nByte = nPassOfft; - pComp = &pOut->sPass; - pComp->zString = &zUri[nPassOfft+sizeof(char)]; - pComp->nByte = nPos - nPassOfft - 1; - } - /* Update the cursor */ - zUri = &zUri[nPos+1]; - }else{ - zUri++; - } - } - pComp = &pOut->sHost; - while( zUri < zCur && SyisSpace(zUri[0])){ - zUri++; - } - SyStringInitFromBuf(pComp, zUri, (sxu32)(zCur - zUri)); - if( pComp->zString[0] == '[' ){ - /* An IPv6 Address: Make a simple naive test - */ - zUri++; pComp->zString++; pComp->nByte = 0; - while( ((unsigned char)zUri[0] < 0xc0 && SyisHex(zUri[0])) || zUri[0] == ':' ){ - zUri++; pComp->nByte++; - } - if( zUri[0] != ']' ){ - return SXERR_CORRUPT; /* Malformed IPv6 address */ - } - zUri++; - bIPv6 = TRUE; - } - /* Extract a port number if available */ - rc = SyByteFind(zUri, (sxu32)(zCur - zUri), ':', &nPos); - if( rc == SXRET_OK ){ - if( bIPv6 == FALSE ){ - pComp->nByte = (sxu32)(&zUri[nPos] - zUri); - } - pComp = &pOut->sPort; - SyStringInitFromBuf(pComp, &zUri[nPos+1], (sxu32)(zCur - &zUri[nPos+1])); - } - if( bHostOnly == TRUE ){ - return SXRET_OK; - } -PathSplit: - zUri = zCur; - pComp = &pOut->sPath; - SyStringInitFromBuf(pComp, zUri, (sxu32)(zEnd-zUri)); - if( pComp->nByte == 0 ){ - return SXRET_OK; /* Empty path */ - } - if( SXRET_OK == SyByteFind(zUri, (sxu32)(zEnd-zUri), '?', &nPos) ){ - pComp->nByte = nPos; /* Update path length */ - pComp = &pOut->sQuery; - SyStringInitFromBuf(pComp, &zUri[nPos+1], (sxu32)(zEnd-&zUri[nPos+1])); - } - if( SXRET_OK == SyByteFind(zUri, (sxu32)(zEnd-zUri), '#', &nPos) ){ - /* Update path or query length */ - if( pComp == &pOut->sPath ){ - pComp->nByte = nPos; - }else{ - if( &zUri[nPos] < (char *)SyStringData(pComp) ){ - /* Malformed syntax : Query must be present before fragment */ - return SXERR_SYNTAX; - } - pComp->nByte -= (sxu32)(zEnd - &zUri[nPos]); - } - pComp = &pOut->sFragment; - SyStringInitFromBuf(pComp, &zUri[nPos+1], (sxu32)(zEnd-&zUri[nPos+1])) - } - return SXRET_OK; - } - /* - * Extract a single line from a raw HTTP request. - * Return SXRET_OK on success, SXERR_EOF when end of input - * and SXERR_MORE when more input is needed. - */ -static sxi32 VmGetNextLine(SyString *pCursor, SyString *pCurrent) -{ - const char *zIn; - sxu32 nPos; - /* Jump leading white spaces */ - SyStringLeftTrim(pCursor); - if( pCursor->nByte < 1 ){ - SyStringInitFromBuf(pCurrent, 0, 0); - return SXERR_EOF; /* End of input */ - } - zIn = SyStringData(pCursor); - if( SXRET_OK != SyByteListFind(pCursor->zString, pCursor->nByte, "\r\n", &nPos) ){ - /* Line not found, tell the caller to read more input from source */ - SyStringDupPtr(pCurrent, pCursor); - return SXERR_MORE; - } - pCurrent->zString = zIn; - pCurrent->nByte = nPos; - /* advance the cursor so we can call this routine again */ - pCursor->zString = &zIn[nPos]; - pCursor->nByte -= nPos; - return SXRET_OK; - } - /* - * Split a single MIME header into a name value pair. - * This function return SXRET_OK, SXERR_CONTINUE on success. - * Otherwise SXERR_NEXT is returned when a malformed header - * is encountered. - * Note: This function handle also mult-line headers. - */ - static sxi32 VmHttpProcessOneHeader(SyhttpHeader *pHdr, SyhttpHeader *pLast, const char *zLine, sxu32 nLen) - { - SyString *pName; - sxu32 nPos; - sxi32 rc; - if( nLen < 1 ){ - return SXERR_NEXT; - } - /* Check for multi-line header */ - if( pLast && (zLine[-1] == ' ' || zLine[-1] == '\t') ){ - SyString *pTmp = &pLast->sValue; - SyStringFullTrim(pTmp); - if( pTmp->nByte == 0 ){ - SyStringInitFromBuf(pTmp, zLine, nLen); - }else{ - /* Update header value length */ - pTmp->nByte = (sxu32)(&zLine[nLen] - pTmp->zString); - } - /* Simply tell the caller to reset its states and get another line */ - return SXERR_CONTINUE; - } - /* Split the header */ - pName = &pHdr->sName; - rc = SyByteFind(zLine, nLen, ':', &nPos); - if(rc != SXRET_OK ){ - return SXERR_NEXT; /* Malformed header;Check the next entry */ - } - SyStringInitFromBuf(pName, zLine, nPos); - SyStringFullTrim(pName); - /* Extract a header value */ - SyStringInitFromBuf(&pHdr->sValue, &zLine[nPos + 1], nLen - nPos - 1); - /* Remove leading and trailing whitespaces */ - SyStringFullTrim(&pHdr->sValue); - return SXRET_OK; - } - /* - * Extract all MIME headers associated with a HTTP request. - * After processing the first line of a HTTP request, the following - * routine is called in order to extract MIME headers. - * This function return SXRET_OK on success, SXERR_MORE when it needs - * more inputs. - * Note: Any malformed header is simply discarded. - */ - static sxi32 VmHttpExtractHeaders(SyString *pRequest, SySet *pOut) - { - SyhttpHeader *pLast = 0; - SyString sCurrent; - SyhttpHeader sHdr; - sxu8 bEol; - sxi32 rc; - if( SySetUsed(pOut) > 0 ){ - pLast = (SyhttpHeader *)SySetAt(pOut, SySetUsed(pOut)-1); - } - bEol = FALSE; - for(;;){ - SyZero(&sHdr, sizeof(SyhttpHeader)); - /* Extract a single line from the raw HTTP request */ - rc = VmGetNextLine(pRequest, &sCurrent); - if(rc != SXRET_OK ){ - if( sCurrent.nByte < 1 ){ - break; - } - bEol = TRUE; - } - /* Process the header */ - if( SXRET_OK == VmHttpProcessOneHeader(&sHdr, pLast, sCurrent.zString, sCurrent.nByte)){ - if( SXRET_OK != SySetPut(pOut, (const void *)&sHdr) ){ - break; - } - /* Retrieve the last parsed header so we can handle multi-line header - * in case we face one of them. - */ - pLast = (SyhttpHeader *)SySetPeek(pOut); - } - if( bEol ){ - break; - } - } /* for(;;) */ - return SXRET_OK; - } - /* - * Process the first line of a HTTP request. - * This routine perform the following operations - * 1) Extract the HTTP method. - * 2) Split the request URI to it's fields [ie: host, path, query, ...]. - * 3) Extract the HTTP protocol version. - */ - static sxi32 VmHttpProcessFirstLine( - SyString *pRequest, /* Raw HTTP request */ - sxi32 *pMethod, /* OUT: HTTP method */ - SyhttpUri *pUri, /* OUT: Parse of the URI */ - sxi32 *pProto /* OUT: HTTP protocol */ - ) - { - static const char *azMethods[] = { "get", "post", "head", "put"}; - static const sxi32 aMethods[] = { HTTP_METHOD_GET, HTTP_METHOD_POST, HTTP_METHOD_HEAD, HTTP_METHOD_PUT}; - const char *zIn, *zEnd, *zPtr; - SyString sLine; - sxu32 nLen; - sxi32 rc; - /* Extract the first line and update the pointer */ - rc = VmGetNextLine(pRequest, &sLine); - if( rc != SXRET_OK ){ - return rc; - } - if ( sLine.nByte < 1 ){ - /* Empty HTTP request */ - return SXERR_EMPTY; - } - /* Delimit the line and ignore trailing and leading white spaces */ - zIn = sLine.zString; - zEnd = &zIn[sLine.nByte]; - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ - zIn++; - } - /* Extract the HTTP method */ - zPtr = zIn; - while( zIn < zEnd && !SyisSpace(zIn[0]) ){ - zIn++; - } - *pMethod = HTTP_METHOD_OTHR; - if( zIn > zPtr ){ - sxu32 i; - nLen = (sxu32)(zIn-zPtr); - for( i = 0 ; i < SX_ARRAYSIZE(azMethods) ; ++i ){ - if( SyStrnicmp(azMethods[i], zPtr, nLen) == 0 ){ - *pMethod = aMethods[i]; - break; - } - } - } - /* Jump trailing white spaces */ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ - zIn++; - } - /* Extract the request URI */ - zPtr = zIn; - while( zIn < zEnd && !SyisSpace(zIn[0]) ){ - zIn++; - } - if( zIn > zPtr ){ - nLen = (sxu32)(zIn-zPtr); - /* Split raw URI to it's fields */ - VmHttpSplitURI(pUri, zPtr, nLen); - } - /* Jump trailing white spaces */ - while( zIn < zEnd && (unsigned char)zIn[0] < 0xc0 && SyisSpace(zIn[0]) ){ - zIn++; - } - /* Extract the HTTP version */ - zPtr = zIn; - while( zIn < zEnd && !SyisSpace(zIn[0]) ){ - zIn++; - } - *pProto = HTTP_PROTO_11; /* HTTP/1.1 */ - rc = 1; - if( zIn > zPtr ){ - rc = SyStrnicmp(zPtr, "http/1.0", (sxu32)(zIn-zPtr)); - } - if( !rc ){ - *pProto = HTTP_PROTO_10; /* HTTP/1.0 */ - } - return SXRET_OK; - } - /* - * Tokenize, decode and split a raw query encoded as: "x-www-form-urlencoded" - * into a name value pair. - * Note that this encoding is implicit in GET based requests. - * After the tokenization process, register the decoded queries - * in the $_GET/$_POST/$_REQUEST superglobals arrays. - */ - static sxi32 VmHttpSplitEncodedQuery( - jx9_vm *pVm, /* Target VM */ - SyString *pQuery, /* Raw query to decode */ - SyBlob *pWorker, /* Working buffer */ - int is_post /* TRUE if we are dealing with a POST request */ - ) - { - const char *zEnd = &pQuery->zString[pQuery->nByte]; - const char *zIn = pQuery->zString; - jx9_value *pGet, *pRequest; - SyString sName, sValue; - const char *zPtr; - sxu32 nBlobOfft; - /* Extract superglobals */ - if( is_post ){ - /* $_POST superglobal */ - pGet = VmExtractSuper(&(*pVm), "_POST", sizeof("_POST")-1); - }else{ - /* $_GET superglobal */ - pGet = VmExtractSuper(&(*pVm), "_GET", sizeof("_GET")-1); - } - pRequest = VmExtractSuper(&(*pVm), "_REQUEST", sizeof("_REQUEST")-1); - /* Split up the raw query */ - for(;;){ - /* Jump leading white spaces */ - while(zIn < zEnd && SyisSpace(zIn[0]) ){ - zIn++; - } - if( zIn >= zEnd ){ - break; - } - zPtr = zIn; - while( zPtr < zEnd && zPtr[0] != '=' && zPtr[0] != '&' && zPtr[0] != ';' ){ - zPtr++; - } - /* Reset the working buffer */ - SyBlobReset(pWorker); - /* Decode the entry */ - SyUriDecode(zIn, (sxu32)(zPtr-zIn), jx9VmBlobConsumer, pWorker, TRUE); - /* Save the entry */ - sName.nByte = SyBlobLength(pWorker); - sValue.zString = 0; - sValue.nByte = 0; - if( zPtr < zEnd && zPtr[0] == '=' ){ - zPtr++; - zIn = zPtr; - /* Store field value */ - while( zPtr < zEnd && zPtr[0] != '&' && zPtr[0] != ';' ){ - zPtr++; - } - if( zPtr > zIn ){ - /* Decode the value */ - nBlobOfft = SyBlobLength(pWorker); - SyUriDecode(zIn, (sxu32)(zPtr-zIn), jx9VmBlobConsumer, pWorker, TRUE); - sValue.zString = (const char *)SyBlobDataAt(pWorker, nBlobOfft); - sValue.nByte = SyBlobLength(pWorker) - nBlobOfft; - - } - /* Synchronize pointers */ - zIn = zPtr; - } - sName.zString = (const char *)SyBlobData(pWorker); - /* Install the decoded query in the $_GET/$_REQUEST array */ - if( pGet && (pGet->iFlags & MEMOBJ_HASHMAP) ){ - VmHashmapInsert((jx9_hashmap *)pGet->x.pOther, - sName.zString, (int)sName.nByte, - sValue.zString, (int)sValue.nByte - ); - } - if( pRequest && (pRequest->iFlags & MEMOBJ_HASHMAP) ){ - VmHashmapInsert((jx9_hashmap *)pRequest->x.pOther, - sName.zString, (int)sName.nByte, - sValue.zString, (int)sValue.nByte - ); - } - /* Advance the pointer */ - zIn = &zPtr[1]; - } - /* All done*/ - return SXRET_OK; - } - /* - * Extract MIME header value from the given set. - * Return header value on success. NULL otherwise. - */ - static SyString * VmHttpExtractHeaderValue(SySet *pSet, const char *zMime, sxu32 nByte) - { - SyhttpHeader *aMime, *pMime; - SyString sMime; - sxu32 n; - SyStringInitFromBuf(&sMime, zMime, nByte); - /* Point to the MIME entries */ - aMime = (SyhttpHeader *)SySetBasePtr(pSet); - /* Perform the lookup */ - for( n = 0 ; n < SySetUsed(pSet) ; ++n ){ - pMime = &aMime[n]; - if( SyStringCmp(&sMime, &pMime->sName, SyStrnicmp) == 0 ){ - /* Header found, return it's associated value */ - return &pMime->sValue; - } - } - /* No such MIME header */ - return 0; - } - /* - * Tokenize and decode a raw "Cookie:" MIME header into a name value pair - * and insert it's fields [i.e name, value] in the $_COOKIE superglobal. - */ - static sxi32 VmHttpPorcessCookie(jx9_vm *pVm, SyBlob *pWorker, const char *zIn, sxu32 nByte) - { - const char *zPtr, *zDelimiter, *zEnd = &zIn[nByte]; - SyString sName, sValue; - jx9_value *pCookie; - sxu32 nOfft; - /* Make sure the $_COOKIE superglobal is available */ - pCookie = VmExtractSuper(&(*pVm), "_COOKIE", sizeof("_COOKIE")-1); - if( pCookie == 0 || (pCookie->iFlags & MEMOBJ_HASHMAP) == 0 ){ - /* $_COOKIE superglobal not available */ - return SXERR_NOTFOUND; - } - for(;;){ - /* Jump leading white spaces */ - while( zIn < zEnd && SyisSpace(zIn[0]) ){ - zIn++; - } - if( zIn >= zEnd ){ - break; - } - /* Reset the working buffer */ - SyBlobReset(pWorker); - zDelimiter = zIn; - /* Delimit the name[=value]; pair */ - while( zDelimiter < zEnd && zDelimiter[0] != ';' ){ - zDelimiter++; - } - zPtr = zIn; - while( zPtr < zDelimiter && zPtr[0] != '=' ){ - zPtr++; - } - /* Decode the cookie */ - SyUriDecode(zIn, (sxu32)(zPtr-zIn), jx9VmBlobConsumer, pWorker, TRUE); - sName.nByte = SyBlobLength(pWorker); - zPtr++; - sValue.zString = 0; - sValue.nByte = 0; - if( zPtr < zDelimiter ){ - /* Got a Cookie value */ - nOfft = SyBlobLength(pWorker); - SyUriDecode(zPtr, (sxu32)(zDelimiter-zPtr), jx9VmBlobConsumer, pWorker, TRUE); - SyStringInitFromBuf(&sValue, SyBlobDataAt(pWorker, nOfft), SyBlobLength(pWorker)-nOfft); - } - /* Synchronize pointers */ - zIn = &zDelimiter[1]; - /* Perform the insertion */ - sName.zString = (const char *)SyBlobData(pWorker); - VmHashmapInsert((jx9_hashmap *)pCookie->x.pOther, - sName.zString, (int)sName.nByte, - sValue.zString, (int)sValue.nByte - ); - } - return SXRET_OK; - } - /* - * Process a full HTTP request and populate the appropriate arrays - * such as $_SERVER, $_GET, $_POST, $_COOKIE, $_REQUEST, ... with the information - * extracted from the raw HTTP request. As an extension Symisc introduced - * the $_HEADER array which hold a copy of the processed HTTP MIME headers - * and their associated values. [i.e: $_HEADER['Server'], $_HEADER['User-Agent'], ...]. - * This function return SXRET_OK on success. Any other return value indicates - * a malformed HTTP request. - */ - static sxi32 VmHttpProcessRequest(jx9_vm *pVm, const char *zRequest, int nByte) - { - SyString *pName, *pValue, sRequest; /* Raw HTTP request */ - jx9_value *pHeaderArray; /* $_HEADER superglobal (Symisc eXtension to the JX9 specification)*/ - SyhttpHeader *pHeader; /* MIME header */ - SyhttpUri sUri; /* Parse of the raw URI*/ - SyBlob sWorker; /* General purpose working buffer */ - SySet sHeader; /* MIME headers set */ - sxi32 iMethod; /* HTTP method [i.e: GET, POST, HEAD...]*/ - sxi32 iVer; /* HTTP protocol version */ - sxi32 rc; - SyStringInitFromBuf(&sRequest, zRequest, nByte); - SySetInit(&sHeader, &pVm->sAllocator, sizeof(SyhttpHeader)); - SyBlobInit(&sWorker, &pVm->sAllocator); - /* Ignore leading and trailing white spaces*/ - SyStringFullTrim(&sRequest); - /* Process the first line */ - rc = VmHttpProcessFirstLine(&sRequest, &iMethod, &sUri, &iVer); - if( rc != SXRET_OK ){ - return rc; - } - /* Process MIME headers */ - VmHttpExtractHeaders(&sRequest, &sHeader); - /* - * Setup $_SERVER environments - */ - /* 'SERVER_PROTOCOL': Name and revision of the information protocol via which the page was requested */ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "SERVER_PROTOCOL", - iVer == HTTP_PROTO_10 ? "HTTP/1.0" : "HTTP/1.1", - sizeof("HTTP/1.1")-1 - ); - /* 'REQUEST_METHOD': Which request method was used to access the page */ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "REQUEST_METHOD", - iMethod == HTTP_METHOD_GET ? "GET" : - (iMethod == HTTP_METHOD_POST ? "POST": - (iMethod == HTTP_METHOD_PUT ? "PUT" : - (iMethod == HTTP_METHOD_HEAD ? "HEAD" : "OTHER"))), - -1 /* Compute attribute length automatically */ - ); - if( SyStringLength(&sUri.sQuery) > 0 && iMethod == HTTP_METHOD_GET ){ - pValue = &sUri.sQuery; - /* 'QUERY_STRING': The query string, if any, via which the page was accessed */ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "QUERY_STRING", - pValue->zString, - pValue->nByte - ); - /* Decoded the raw query */ - VmHttpSplitEncodedQuery(&(*pVm), pValue, &sWorker, FALSE); - } - /* REQUEST_URI: The URI which was given in order to access this page; for instance, '/index.html' */ - pValue = &sUri.sRaw; - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "REQUEST_URI", - pValue->zString, - pValue->nByte - ); - /* - * 'PATH_INFO' - * 'ORIG_PATH_INFO' - * Contains any client-provided pathname information trailing the actual script filename but preceding - * the query string, if available. For instance, if the current script was accessed via the URL - * http://www.example.com/jx9/path_info.jx9/some/stuff?foo=bar, then $_SERVER['PATH_INFO'] would contain - * /some/stuff. - */ - pValue = &sUri.sPath; - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "PATH_INFO", - pValue->zString, - pValue->nByte - ); - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "ORIG_PATH_INFO", - pValue->zString, - pValue->nByte - ); - /* 'HTTP_ACCEPT': Contents of the Accept: header from the current request, if there is one */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Accept", sizeof("Accept")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_ACCEPT", - pValue->zString, - pValue->nByte - ); - } - /* 'HTTP_ACCEPT_CHARSET': Contents of the Accept-Charset: header from the current request, if there is one. */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Accept-Charset", sizeof("Accept-Charset")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_ACCEPT_CHARSET", - pValue->zString, - pValue->nByte - ); - } - /* 'HTTP_ACCEPT_ENCODING': Contents of the Accept-Encoding: header from the current request, if there is one. */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Accept-Encoding", sizeof("Accept-Encoding")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_ACCEPT_ENCODING", - pValue->zString, - pValue->nByte - ); - } - /* 'HTTP_ACCEPT_LANGUAGE': Contents of the Accept-Language: header from the current request, if there is one */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Accept-Language", sizeof("Accept-Language")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_ACCEPT_LANGUAGE", - pValue->zString, - pValue->nByte - ); - } - /* 'HTTP_CONNECTION': Contents of the Connection: header from the current request, if there is one. */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Connection", sizeof("Connection")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_CONNECTION", - pValue->zString, - pValue->nByte - ); - } - /* 'HTTP_HOST': Contents of the Host: header from the current request, if there is one. */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Host", sizeof("Host")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_HOST", - pValue->zString, - pValue->nByte - ); - } - /* 'HTTP_REFERER': Contents of the Referer: header from the current request, if there is one. */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Referer", sizeof("Referer")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_REFERER", - pValue->zString, - pValue->nByte - ); - } - /* 'HTTP_USER_AGENT': Contents of the Referer: header from the current request, if there is one. */ - pValue = VmHttpExtractHeaderValue(&sHeader, "User-Agent", sizeof("User-Agent")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "HTTP_USER_AGENT", - pValue->zString, - pValue->nByte - ); - } - /* 'JX9_AUTH_DIGEST': When doing Digest HTTP authentication this variable is set to the 'Authorization' - * header sent by the client (which you should then use to make the appropriate validation). - */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Authorization", sizeof("Authorization")-1); - if( pValue ){ - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "JX9_AUTH_DIGEST", - pValue->zString, - pValue->nByte - ); - jx9_vm_config(pVm, - JX9_VM_CONFIG_SERVER_ATTR, - "JX9_AUTH", - pValue->zString, - pValue->nByte - ); - } - /* Install all clients HTTP headers in the $_HEADER superglobal */ - pHeaderArray = VmExtractSuper(&(*pVm), "_HEADER", sizeof("_HEADER")-1); - /* Iterate throw the available MIME headers*/ - SySetResetCursor(&sHeader); - pHeader = 0; /* stupid cc warning */ - while( SXRET_OK == SySetGetNextEntry(&sHeader, (void **)&pHeader) ){ - pName = &pHeader->sName; - pValue = &pHeader->sValue; - if( pHeaderArray && (pHeaderArray->iFlags & MEMOBJ_HASHMAP)){ - /* Insert the MIME header and it's associated value */ - VmHashmapInsert((jx9_hashmap *)pHeaderArray->x.pOther, - pName->zString, (int)pName->nByte, - pValue->zString, (int)pValue->nByte - ); - } - if( pName->nByte == sizeof("Cookie")-1 && SyStrnicmp(pName->zString, "Cookie", sizeof("Cookie")-1) == 0 - && pValue->nByte > 0){ - /* Process the name=value pair and insert them in the $_COOKIE superglobal array */ - VmHttpPorcessCookie(&(*pVm), &sWorker, pValue->zString, pValue->nByte); - } - } - if( iMethod == HTTP_METHOD_POST ){ - /* Extract raw POST data */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Content-Type", sizeof("Content-Type") - 1); - if( pValue && pValue->nByte >= sizeof("application/x-www-form-urlencoded") - 1 && - SyMemcmp("application/x-www-form-urlencoded", pValue->zString, pValue->nByte) == 0 ){ - /* Extract POST data length */ - pValue = VmHttpExtractHeaderValue(&sHeader, "Content-Length", sizeof("Content-Length") - 1); - if( pValue ){ - sxi32 iLen = 0; /* POST data length */ - SyStrToInt32(pValue->zString, pValue->nByte, (void *)&iLen, 0); - if( iLen > 0 ){ - /* Remove leading and trailing white spaces */ - SyStringFullTrim(&sRequest); - if( (int)sRequest.nByte > iLen ){ - sRequest.nByte = (sxu32)iLen; - } - /* Decode POST data now */ - VmHttpSplitEncodedQuery(&(*pVm), &sRequest, &sWorker, TRUE); - } - } - } - } - /* All done, clean-up the mess left behind */ - SySetRelease(&sHeader); - SyBlobRelease(&sWorker); - return SXRET_OK; - } - -/* - * ---------------------------------------------------------- - * File: lhash_kv.c - * MD5: 581b07ce2984fd95740677285d8a11d3 - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: lhash_kv.c v1.7 Solaris 2013-01-14 12:56 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* - * This file implements disk based hashtable using the linear hashing algorithm. - * This implementation is the one decribed in the paper: - * LINEAR HASHING : A NEW TOOL FOR FILE AND TABLE ADDRESSING. Witold Litwin. I. N. Ft. I. A.. 78 150 Le Chesnay, France. - * Plus a smart extension called Virtual Bucket Table. (contact devel@symisc.net for additional information). - */ -/* Magic number identifying a valid storage image */ -#define L_HASH_MAGIC 0xFA782DCB -/* - * Magic word to hash to identify a valid hash function. - */ -#define L_HASH_WORD "chm@symisc" -/* - * Cell size on disk. - */ -#define L_HASH_CELL_SZ (4/*Hash*/+4/*Key*/+8/*Data*/+2/* Offset of the next cell */+8/*Overflow*/) -/* - * Primary page (not overflow pages) header size on disk. - */ -#define L_HASH_PAGE_HDR_SZ (2/* Cell offset*/+2/* Free block offset*/+8/*Slave page number*/) -/* - * The maximum amount of payload (in bytes) that can be stored locally for - * a database entry. If the entry contains more data than this, the - * extra goes onto overflow pages. -*/ -#define L_HASH_MX_PAYLOAD(PageSize) (PageSize-(L_HASH_PAGE_HDR_SZ+L_HASH_CELL_SZ)) -/* - * Maxium free space on a single page. - */ -#define L_HASH_MX_FREE_SPACE(PageSize) (PageSize - (L_HASH_PAGE_HDR_SZ)) -/* -** The maximum number of bytes of payload allowed on a single overflow page. -*/ -#define L_HASH_OVERFLOW_SIZE(PageSize) (PageSize-8) -/* Forward declaration */ -typedef struct lhash_kv_engine lhash_kv_engine; -typedef struct lhpage lhpage; -/* - * Each record in the database is identified either in-memory or in - * disk by an instance of the following structure. - */ -typedef struct lhcell lhcell; -struct lhcell -{ - /* Disk-data (Big-Endian) */ - sxu32 nHash; /* Hash of the key: 4 bytes */ - sxu32 nKey; /* Key length: 4 bytes */ - sxu64 nData; /* Data length: 8 bytes */ - sxu16 iNext; /* Offset of the next cell: 2 bytes */ - pgno iOvfl; /* Overflow page number if any: 8 bytes */ - /* In-memory data only */ - lhpage *pPage; /* Page this cell belongs */ - sxu16 iStart; /* Offset of this cell */ - pgno iDataPage; /* Data page number when overflow */ - sxu16 iDataOfft; /* Offset of the data in iDataPage */ - SyBlob sKey; /* Record key for fast lookup (Kept in-memory if < 256KB ) */ - lhcell *pNext,*pPrev; /* Linked list of the loaded memory cells */ - lhcell *pNextCol,*pPrevCol; /* Collison chain */ -}; -/* -** Each database page has a header that is an instance of this -** structure. -*/ -typedef struct lhphdr lhphdr; -struct lhphdr -{ - sxu16 iOfft; /* Offset of the first cell */ - sxu16 iFree; /* Offset of the first free block*/ - pgno iSlave; /* Slave page number */ -}; -/* - * Each loaded primary disk page is represented in-memory using - * an instance of the following structure. - */ -struct lhpage -{ - lhash_kv_engine *pHash; /* KV Storage engine that own this page */ - unqlite_page *pRaw; /* Raw page contents */ - lhphdr sHdr; /* Processed page header */ - lhcell **apCell; /* Cell buckets */ - lhcell *pList,*pFirst; /* Linked list of cells */ - sxu32 nCell; /* Total number of cells */ - sxu32 nCellSize; /* apCell[] size */ - lhpage *pMaster; /* Master page in case we are dealing with a slave page */ - lhpage *pSlave; /* List of slave pages */ - lhpage *pNextSlave; /* Next slave page on the list */ - sxi32 iSlave; /* Total number of slave pages */ - sxu16 nFree; /* Amount of free space available in the page */ -}; -/* - * A Bucket map record which is used to map logical bucket number to real - * bucket number is represented by an instance of the following structure. - */ -typedef struct lhash_bmap_rec lhash_bmap_rec; -struct lhash_bmap_rec -{ - pgno iLogic; /* Logical bucket number */ - pgno iReal; /* Real bucket number */ - lhash_bmap_rec *pNext,*pPrev; /* Link to other bucket map */ - lhash_bmap_rec *pNextCol,*pPrevCol; /* Collision links */ -}; -typedef struct lhash_bmap_page lhash_bmap_page; -struct lhash_bmap_page -{ - pgno iNum; /* Page number where this entry is stored */ - sxu16 iPtr; /* Offset to start reading/writing from */ - sxu32 nRec; /* Total number of records in this page */ - pgno iNext; /* Next map page */ -}; -/* - * An in memory linear hash implemenation is represented by in an isntance - * of the following structure. - */ -struct lhash_kv_engine -{ - const unqlite_kv_io *pIo; /* IO methods: Must be first */ - /* Private fields */ - SyMemBackend sAllocator; /* Private memory backend */ - ProcHash xHash; /* Default hash function */ - ProcCmp xCmp; /* Default comparison function */ - unqlite_page *pHeader; /* Page one to identify a valid implementation */ - lhash_bmap_rec **apMap; /* Buckets map records */ - sxu32 nBuckRec; /* Total number of bucket map records */ - sxu32 nBuckSize; /* apMap[] size */ - lhash_bmap_rec *pList; /* List of bucket map records */ - lhash_bmap_rec *pFirst; /* First record*/ - lhash_bmap_page sPageMap; /* Primary bucket map */ - int iPageSize; /* Page size */ - pgno nFreeList; /* List of free pages */ - pgno split_bucket; /* Current split bucket: MUST BE A POWER OF TWO */ - pgno max_split_bucket; /* Maximum split bucket: MUST BE A POWER OF TWO */ - pgno nmax_split_nucket; /* Next maximum split bucket (1 << nMsb): In-memory only */ - sxu32 nMagic; /* Magic number to identify a valid linear hash disk database */ -}; -/* - * Given a logical bucket number, return the record associated with it. - */ -static lhash_bmap_rec * lhMapFindBucket(lhash_kv_engine *pEngine,pgno iLogic) -{ - lhash_bmap_rec *pRec; - if( pEngine->nBuckRec < 1 ){ - /* Don't bother */ - return 0; - } - pRec = pEngine->apMap[iLogic & (pEngine->nBuckSize - 1)]; - for(;;){ - if( pRec == 0 ){ - break; - } - if( pRec->iLogic == iLogic ){ - return pRec; - } - /* Point to the next entry */ - pRec = pRec->pNextCol; - } - /* No such record */ - return 0; -} -/* - * Install a new bucket map record. - */ -static int lhMapInstallBucket(lhash_kv_engine *pEngine,pgno iLogic,pgno iReal) -{ - lhash_bmap_rec *pRec; - sxu32 iBucket; - /* Allocate a new instance */ - pRec = (lhash_bmap_rec *)SyMemBackendPoolAlloc(&pEngine->sAllocator,sizeof(lhash_bmap_rec)); - if( pRec == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pRec,sizeof(lhash_bmap_rec)); - /* Fill in the structure */ - pRec->iLogic = iLogic; - pRec->iReal = iReal; - iBucket = iLogic & (pEngine->nBuckSize - 1); - pRec->pNextCol = pEngine->apMap[iBucket]; - if( pEngine->apMap[iBucket] ){ - pEngine->apMap[iBucket]->pPrevCol = pRec; - } - pEngine->apMap[iBucket] = pRec; - /* Link */ - if( pEngine->pFirst == 0 ){ - pEngine->pFirst = pEngine->pList = pRec; - }else{ - MACRO_LD_PUSH(pEngine->pList,pRec); - } - pEngine->nBuckRec++; - if( (pEngine->nBuckRec >= pEngine->nBuckSize * 3) && pEngine->nBuckRec < 100000 ){ - /* Allocate a new larger table */ - sxu32 nNewSize = pEngine->nBuckSize << 1; - lhash_bmap_rec *pEntry; - lhash_bmap_rec **apNew; - sxu32 n; - - apNew = (lhash_bmap_rec **)SyMemBackendAlloc(&pEngine->sAllocator, nNewSize * sizeof(lhash_bmap_rec *)); - if( apNew ){ - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(lhash_bmap_rec *)); - /* Rehash all entries */ - n = 0; - pEntry = pEngine->pList; - for(;;){ - /* Loop one */ - if( n >= pEngine->nBuckRec ){ - break; - } - pEntry->pNextCol = pEntry->pPrevCol = 0; - /* Install in the new bucket */ - iBucket = pEntry->iLogic & (nNewSize - 1); - pEntry->pNextCol = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevCol = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(&pEngine->sAllocator,(void *)pEngine->apMap); - pEngine->apMap = apNew; - pEngine->nBuckSize = nNewSize; - } - } - return UNQLITE_OK; -} -/* - * Process a raw bucket map record. - */ -static int lhMapLoadPage(lhash_kv_engine *pEngine,lhash_bmap_page *pMap,const unsigned char *zRaw) -{ - const unsigned char *zEnd = &zRaw[pEngine->iPageSize]; - const unsigned char *zPtr = zRaw; - pgno iLogic,iReal; - sxu32 n; - int rc; - if( pMap->iPtr == 0 ){ - /* Read the map header */ - SyBigEndianUnpack64(zRaw,&pMap->iNext); - zRaw += 8; - SyBigEndianUnpack32(zRaw,&pMap->nRec); - zRaw += 4; - }else{ - /* Mostly page one of the database */ - zRaw += pMap->iPtr; - } - /* Start processing */ - for( n = 0; n < pMap->nRec ; ++n ){ - if( zRaw >= zEnd ){ - break; - } - /* Extract the logical and real bucket number */ - SyBigEndianUnpack64(zRaw,&iLogic); - zRaw += 8; - SyBigEndianUnpack64(zRaw,&iReal); - zRaw += 8; - /* Install the record in the map */ - rc = lhMapInstallBucket(pEngine,iLogic,iReal); - if( rc != UNQLITE_OK ){ - return rc; - } - } - pMap->iPtr = (sxu16)(zRaw-zPtr); - /* All done */ - return UNQLITE_OK; -} -/* - * Allocate a new cell instance. - */ -static lhcell * lhNewCell(lhash_kv_engine *pEngine,lhpage *pPage) -{ - lhcell *pCell; - pCell = (lhcell *)SyMemBackendPoolAlloc(&pEngine->sAllocator,sizeof(lhcell)); - if( pCell == 0 ){ - return 0; - } - /* Zero the structure */ - SyZero(pCell,sizeof(lhcell)); - /* Fill in the structure */ - SyBlobInit(&pCell->sKey,&pEngine->sAllocator); - pCell->pPage = pPage; - return pCell; -} -/* - * Discard a cell from the page table. - */ -static void lhCellDiscard(lhcell *pCell) -{ - lhpage *pPage = pCell->pPage->pMaster; - - if( pCell->pPrevCol ){ - pCell->pPrevCol->pNextCol = pCell->pNextCol; - }else{ - pPage->apCell[pCell->nHash & (pPage->nCellSize - 1)] = pCell->pNextCol; - } - if( pCell->pNextCol ){ - pCell->pNextCol->pPrevCol = pCell->pPrevCol; - } - MACRO_LD_REMOVE(pPage->pList,pCell); - if( pCell == pPage->pFirst ){ - pPage->pFirst = pCell->pPrev; - } - pPage->nCell--; - /* Release the cell */ - SyBlobRelease(&pCell->sKey); - SyMemBackendPoolFree(&pPage->pHash->sAllocator,pCell); -} -/* - * Install a cell in the page table. - */ -static int lhInstallCell(lhcell *pCell) -{ - lhpage *pPage = pCell->pPage->pMaster; - sxu32 iBucket; - if( pPage->nCell < 1 ){ - sxu32 nTableSize = 32; /* Must be a power of two */ - lhcell **apTable; - /* Allocate a new cell table */ - apTable = (lhcell **)SyMemBackendAlloc(&pPage->pHash->sAllocator, nTableSize * sizeof(lhcell *)); - if( apTable == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the new table */ - SyZero((void *)apTable, nTableSize * sizeof(lhcell *)); - /* Install it */ - pPage->apCell = apTable; - pPage->nCellSize = nTableSize; - } - iBucket = pCell->nHash & (pPage->nCellSize - 1); - pCell->pNextCol = pPage->apCell[iBucket]; - if( pPage->apCell[iBucket] ){ - pPage->apCell[iBucket]->pPrevCol = pCell; - } - pPage->apCell[iBucket] = pCell; - if( pPage->pFirst == 0 ){ - pPage->pFirst = pPage->pList = pCell; - }else{ - MACRO_LD_PUSH(pPage->pList,pCell); - } - pPage->nCell++; - if( (pPage->nCell >= pPage->nCellSize * 3) && pPage->nCell < 100000 ){ - /* Allocate a new larger table */ - sxu32 nNewSize = pPage->nCellSize << 1; - lhcell *pEntry; - lhcell **apNew; - sxu32 n; - - apNew = (lhcell **)SyMemBackendAlloc(&pPage->pHash->sAllocator, nNewSize * sizeof(lhcell *)); - if( apNew ){ - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(lhcell *)); - /* Rehash all entries */ - n = 0; - pEntry = pPage->pList; - for(;;){ - /* Loop one */ - if( n >= pPage->nCell ){ - break; - } - pEntry->pNextCol = pEntry->pPrevCol = 0; - /* Install in the new bucket */ - iBucket = pEntry->nHash & (nNewSize - 1); - pEntry->pNextCol = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevCol = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(&pPage->pHash->sAllocator,(void *)pPage->apCell); - pPage->apCell = apNew; - pPage->nCellSize = nNewSize; - } - } - return UNQLITE_OK; -} -/* - * Private data of lhKeyCmp(). - */ -struct lhash_key_cmp -{ - const char *zIn; /* Start of the stream */ - const char *zEnd; /* End of the stream */ - ProcCmp xCmp; /* Comparison function */ -}; -/* - * Comparsion callback for large key > 256 KB - */ -static int lhKeyCmp(const void *pData,sxu32 nLen,void *pUserData) -{ - struct lhash_key_cmp *pCmp = (struct lhash_key_cmp *)pUserData; - int rc; - if( pCmp->zIn >= pCmp->zEnd ){ - if( nLen > 0 ){ - return UNQLITE_ABORT; - } - return UNQLITE_OK; - } - /* Perform the comparison */ - rc = pCmp->xCmp((const void *)pCmp->zIn,pData,nLen); - if( rc != 0 ){ - /* Abort comparison */ - return UNQLITE_ABORT; - } - /* Advance the cursor */ - pCmp->zIn += nLen; - return UNQLITE_OK; -} -/* Forward declaration */ -static int lhConsumeCellkey(lhcell *pCell,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData,int offt_only); -/* - * given a key, return the cell associated with it on success. NULL otherwise. - */ -static lhcell * lhFindCell( - lhpage *pPage, /* Target page */ - const void *pKey, /* Lookup key */ - sxu32 nByte, /* Key length */ - sxu32 nHash /* Hash of the key */ - ) -{ - lhcell *pEntry; - if( pPage->nCell < 1 ){ - /* Don't bother hashing */ - return 0; - } - /* Point to the corresponding bucket */ - pEntry = pPage->apCell[nHash & (pPage->nCellSize - 1)]; - for(;;){ - if( pEntry == 0 ){ - break; - } - if( pEntry->nHash == nHash && pEntry->nKey == nByte ){ - if( SyBlobLength(&pEntry->sKey) < 1 ){ - /* Large key (> 256 KB) are not kept in-memory */ - struct lhash_key_cmp sCmp; - int rc; - /* Fill-in the structure */ - sCmp.zIn = (const char *)pKey; - sCmp.zEnd = &sCmp.zIn[nByte]; - sCmp.xCmp = pPage->pHash->xCmp; - /* Fetch the key from disk and perform the comparison */ - rc = lhConsumeCellkey(pEntry,lhKeyCmp,&sCmp,0); - if( rc == UNQLITE_OK ){ - /* Cell found */ - return pEntry; - } - }else if ( pPage->pHash->xCmp(pKey,SyBlobData(&pEntry->sKey),nByte) == 0 ){ - /* Cell found */ - return pEntry; - } - } - /* Point to the next entry */ - pEntry = pEntry->pNextCol; - } - /* No such entry */ - return 0; -} -/* - * Parse a raw cell fetched from disk. - */ -static int lhParseOneCell(lhpage *pPage,const unsigned char *zRaw,const unsigned char *zEnd,lhcell **ppOut) -{ - sxu16 iNext,iOfft; - sxu32 iHash,nKey; - lhcell *pCell; - sxu64 nData; - int rc; - /* Offset this cell is stored */ - iOfft = (sxu16)(zRaw - (const unsigned char *)pPage->pRaw->zData); - /* 4 byte hash number */ - SyBigEndianUnpack32(zRaw,&iHash); - zRaw += 4; - /* 4 byte key length */ - SyBigEndianUnpack32(zRaw,&nKey); - zRaw += 4; - /* 8 byte data length */ - SyBigEndianUnpack64(zRaw,&nData); - zRaw += 8; - /* 2 byte offset of the next cell */ - SyBigEndianUnpack16(zRaw,&iNext); - /* Perform a sanity check */ - if( iNext > 0 && &pPage->pRaw->zData[iNext] >= zEnd ){ - return UNQLITE_CORRUPT; - } - zRaw += 2; - pCell = lhNewCell(pPage->pHash,pPage); - if( pCell == 0 ){ - return UNQLITE_NOMEM; - } - /* Fill in the structure */ - pCell->iNext = iNext; - pCell->nKey = nKey; - pCell->nData = nData; - pCell->nHash = iHash; - /* Overflow page if any */ - SyBigEndianUnpack64(zRaw,&pCell->iOvfl); - zRaw += 8; - /* Cell offset */ - pCell->iStart = iOfft; - /* Consume the key */ - rc = lhConsumeCellkey(pCell,unqliteDataConsumer,&pCell->sKey,pCell->nKey > 262144 /* 256 KB */? 1 : 0); - if( rc != UNQLITE_OK ){ - /* TICKET: 14-32-chm@symisc.net: Key too large for memory */ - SyBlobRelease(&pCell->sKey); - } - /* Finally install the cell */ - rc = lhInstallCell(pCell); - if( rc != UNQLITE_OK ){ - return rc; - } - if( ppOut ){ - *ppOut = pCell; - } - return UNQLITE_OK; -} -/* - * Compute the total number of free space on a given page. - */ -static int lhPageFreeSpace(lhpage *pPage) -{ - const unsigned char *zEnd,*zRaw = pPage->pRaw->zData; - lhphdr *pHdr = &pPage->sHdr; - sxu16 iNext,iAmount; - sxu16 nFree = 0; - if( pHdr->iFree < 1 ){ - /* Don't bother processing, the page is full */ - pPage->nFree = 0; - return UNQLITE_OK; - } - /* Point to first free block */ - zEnd = &zRaw[pPage->pHash->iPageSize]; - zRaw += pHdr->iFree; - for(;;){ - /* Offset of the next free block */ - SyBigEndianUnpack16(zRaw,&iNext); - zRaw += 2; - /* Available space on this block */ - SyBigEndianUnpack16(zRaw,&iAmount); - nFree += iAmount; - if( iNext < 1 ){ - /* No more free blocks */ - break; - } - /* Point to the next free block*/ - zRaw = &pPage->pRaw->zData[iNext]; - if( zRaw >= zEnd ){ - /* Corrupt page */ - return UNQLITE_CORRUPT; - } - } - /* Save the amount of free space */ - pPage->nFree = nFree; - return UNQLITE_OK; -} -/* - * Given a primary page, load all its cell. - */ -static int lhLoadCells(lhpage *pPage) -{ - const unsigned char *zEnd,*zRaw = pPage->pRaw->zData; - lhphdr *pHdr = &pPage->sHdr; - lhcell *pCell = 0; /* cc warning */ - int rc; - /* Calculate the amount of free space available first */ - rc = lhPageFreeSpace(pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pHdr->iOfft < 1 ){ - /* Don't bother processing, the page is empty */ - return UNQLITE_OK; - } - /* Point to first cell */ - zRaw += pHdr->iOfft; - zEnd = &zRaw[pPage->pHash->iPageSize]; - for(;;){ - /* Parse a single cell */ - rc = lhParseOneCell(pPage,zRaw,zEnd,&pCell); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pCell->iNext < 1 ){ - /* No more cells */ - break; - } - /* Point to the next cell */ - zRaw = &pPage->pRaw->zData[pCell->iNext]; - if( zRaw >= zEnd ){ - /* Corrupt page */ - return UNQLITE_CORRUPT; - } - } - /* All done */ - return UNQLITE_OK; -} -/* - * Given a page, parse its raw headers. - */ -static int lhParsePageHeader(lhpage *pPage) -{ - const unsigned char *zRaw = pPage->pRaw->zData; - lhphdr *pHdr = &pPage->sHdr; - /* Offset of the first cell */ - SyBigEndianUnpack16(zRaw,&pHdr->iOfft); - zRaw += 2; - /* Offset of the first free block */ - SyBigEndianUnpack16(zRaw,&pHdr->iFree); - zRaw += 2; - /* Slave page number */ - SyBigEndianUnpack64(zRaw,&pHdr->iSlave); - /* All done */ - return UNQLITE_OK; -} -/* - * Allocate a new page instance. - */ -static lhpage * lhNewPage( - lhash_kv_engine *pEngine, /* KV store which own this instance */ - unqlite_page *pRaw, /* Raw page contents */ - lhpage *pMaster /* Master page in case we are dealing with a slave page */ - ) -{ - lhpage *pPage; - /* Allocate a new instance */ - pPage = (lhpage *)SyMemBackendPoolAlloc(&pEngine->sAllocator,sizeof(lhpage)); - if( pPage == 0 ){ - return 0; - } - /* Zero the structure */ - SyZero(pPage,sizeof(lhpage)); - /* Fill-in the structure */ - pPage->pHash = pEngine; - pPage->pRaw = pRaw; - pPage->pMaster = pMaster ? pMaster /* Slave page */ : pPage /* Master page */ ; - if( pPage->pMaster != pPage ){ - /* Slave page, attach it to its master */ - pPage->pNextSlave = pMaster->pSlave; - pMaster->pSlave = pPage; - pMaster->iSlave++; - } - /* Save this instance for future fast lookup */ - pRaw->pUserData = pPage; - /* All done */ - return pPage; -} -/* - * Load a primary and its associated slave pages from disk. - */ -static int lhLoadPage(lhash_kv_engine *pEngine,pgno pnum,lhpage *pMaster,lhpage **ppOut,int iNest) -{ - unqlite_page *pRaw; - lhpage *pPage = 0; /* cc warning */ - int rc; - /* Aquire the page from the pager first */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pnum,&pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pRaw->pUserData ){ - /* The page is already parsed and loaded in memory. Point to it */ - pPage = (lhpage *)pRaw->pUserData; - }else{ - /* Allocate a new page */ - pPage = lhNewPage(pEngine,pRaw,pMaster); - if( pPage == 0 ){ - return UNQLITE_NOMEM; - } - /* Process the page */ - rc = lhParsePageHeader(pPage); - if( rc == UNQLITE_OK ){ - /* Load cells */ - rc = lhLoadCells(pPage); - } - if( rc != UNQLITE_OK ){ - pEngine->pIo->xPageUnref(pPage->pRaw); /* pPage will be released inside this call */ - return rc; - } - if( pPage->sHdr.iSlave > 0 && iNest < 128 ){ - if( pMaster == 0 ){ - pMaster = pPage; - } - /* Slave page. Not a fatal error if something goes wrong here */ - lhLoadPage(pEngine,pPage->sHdr.iSlave,pMaster,0,iNest++); - } - } - if( ppOut ){ - *ppOut = pPage; - } - return UNQLITE_OK; -} -/* - * Given a cell, Consume its key by invoking the given callback for each extracted chunk. - */ -static int lhConsumeCellkey( - lhcell *pCell, /* Target cell */ - int (*xConsumer)(const void *,unsigned int,void *), /* Consumer callback */ - void *pUserData, /* Last argument to xConsumer() */ - int offt_only - ) -{ - lhpage *pPage = pCell->pPage; - const unsigned char *zRaw = pPage->pRaw->zData; - const unsigned char *zPayload; - int rc; - /* Point to the payload area */ - zPayload = &zRaw[pCell->iStart]; - if( pCell->iOvfl == 0 ){ - /* Best scenario, consume the key directly without any overflow page */ - zPayload += L_HASH_CELL_SZ; - rc = xConsumer((const void *)zPayload,pCell->nKey,pUserData); - if( rc != UNQLITE_OK ){ - rc = UNQLITE_ABORT; - } - }else{ - lhash_kv_engine *pEngine = pPage->pHash; - sxu32 nByte,nData = pCell->nKey; - unqlite_page *pOvfl; - int data_offset = 0; - pgno iOvfl; - /* Overflow page */ - iOvfl = pCell->iOvfl; - /* Total usable bytes in an overflow page */ - nByte = L_HASH_OVERFLOW_SIZE(pEngine->iPageSize); - for(;;){ - if( iOvfl == 0 || nData < 1 ){ - /* no more overflow page */ - break; - } - /* Point to the overflow page */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - zPayload = &pOvfl->zData[8]; - /* Point to the raw content */ - if( !data_offset ){ - /* Get the data page and offset */ - SyBigEndianUnpack64(zPayload,&pCell->iDataPage); - zPayload += 8; - SyBigEndianUnpack16(zPayload,&pCell->iDataOfft); - zPayload += 2; - if( offt_only ){ - /* Key too large, grab the data offset and return */ - pEngine->pIo->xPageUnref(pOvfl); - return UNQLITE_OK; - } - data_offset = 1; - } - /* Consume the key */ - if( nData <= nByte ){ - rc = xConsumer((const void *)zPayload,nData,pUserData); - if( rc != UNQLITE_OK ){ - pEngine->pIo->xPageUnref(pOvfl); - return UNQLITE_ABORT; - } - nData = 0; - }else{ - rc = xConsumer((const void *)zPayload,nByte,pUserData); - if( rc != UNQLITE_OK ){ - pEngine->pIo->xPageUnref(pOvfl); - return UNQLITE_ABORT; - } - nData -= nByte; - } - /* Next overflow page in the chain */ - SyBigEndianUnpack64(pOvfl->zData,&iOvfl); - /* Unref the page */ - pEngine->pIo->xPageUnref(pOvfl); - } - rc = UNQLITE_OK; - } - return rc; -} -/* - * Given a cell, Consume its data by invoking the given callback for each extracted chunk. - */ -static int lhConsumeCellData( - lhcell *pCell, /* Target cell */ - int (*xConsumer)(const void *,unsigned int,void *), /* Data consumer callback */ - void *pUserData /* Last argument to xConsumer() */ - ) -{ - lhpage *pPage = pCell->pPage; - const unsigned char *zRaw = pPage->pRaw->zData; - const unsigned char *zPayload; - int rc; - /* Point to the payload area */ - zPayload = &zRaw[pCell->iStart]; - if( pCell->iOvfl == 0 ){ - /* Best scenario, consume the data directly without any overflow page */ - zPayload += L_HASH_CELL_SZ + pCell->nKey; - rc = xConsumer((const void *)zPayload,(sxu32)pCell->nData,pUserData); - if( rc != UNQLITE_OK ){ - rc = UNQLITE_ABORT; - } - }else{ - lhash_kv_engine *pEngine = pPage->pHash; - sxu64 nData = pCell->nData; - unqlite_page *pOvfl; - int fix_offset = 0; - sxu32 nByte; - pgno iOvfl; - /* Overflow page where data is stored */ - iOvfl = pCell->iDataPage; - for(;;){ - if( iOvfl == 0 || nData < 1 ){ - /* no more overflow page */ - break; - } - /* Point to the overflow page */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Point to the raw content */ - zPayload = pOvfl->zData; - if( !fix_offset ){ - /* Point to the data */ - zPayload += pCell->iDataOfft; - nByte = pEngine->iPageSize - pCell->iDataOfft; - fix_offset = 1; - }else{ - zPayload += 8; - /* Total usable bytes in an overflow page */ - nByte = L_HASH_OVERFLOW_SIZE(pEngine->iPageSize); - } - /* Consume the data */ - if( nData <= (sxu64)nByte ){ - rc = xConsumer((const void *)zPayload,(unsigned int)nData,pUserData); - if( rc != UNQLITE_OK ){ - pEngine->pIo->xPageUnref(pOvfl); - return UNQLITE_ABORT; - } - nData = 0; - }else{ - if( nByte > 0 ){ - rc = xConsumer((const void *)zPayload,nByte,pUserData); - if( rc != UNQLITE_OK ){ - pEngine->pIo->xPageUnref(pOvfl); - return UNQLITE_ABORT; - } - nData -= nByte; - } - } - /* Next overflow page in the chain */ - SyBigEndianUnpack64(pOvfl->zData,&iOvfl); - /* Unref the page */ - pEngine->pIo->xPageUnref(pOvfl); - } - rc = UNQLITE_OK; - } - return rc; -} -/* - * Read the linear hash header (Page one of the database). - */ -static int lhash_read_header(lhash_kv_engine *pEngine,unqlite_page *pHeader) -{ - const unsigned char *zRaw = pHeader->zData; - lhash_bmap_page *pMap; - sxu32 nHash; - int rc; - pEngine->pHeader = pHeader; - /* 4 byte magic number */ - SyBigEndianUnpack32(zRaw,&pEngine->nMagic); - zRaw += 4; - if( pEngine->nMagic != L_HASH_MAGIC ){ - /* Corrupt implementation */ - return UNQLITE_CORRUPT; - } - /* 4 byte hash value to identify a valid hash function */ - SyBigEndianUnpack32(zRaw,&nHash); - zRaw += 4; - /* Sanity check */ - if( pEngine->xHash(L_HASH_WORD,sizeof(L_HASH_WORD)-1) != nHash ){ - /* Different hash function */ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"Invalid hash function"); - return UNQLITE_INVALID; - } - /* List of free pages */ - SyBigEndianUnpack64(zRaw,&pEngine->nFreeList); - zRaw += 8; - /* Current split bucket */ - SyBigEndianUnpack64(zRaw,&pEngine->split_bucket); - zRaw += 8; - /* Maximum split bucket */ - SyBigEndianUnpack64(zRaw,&pEngine->max_split_bucket); - zRaw += 8; - /* Next generation */ - pEngine->nmax_split_nucket = pEngine->max_split_bucket << 1; - /* Initialiaze the bucket map */ - pMap = &pEngine->sPageMap; - /* Fill in the structure */ - pMap->iNum = pHeader->pgno; - /* Next page in the bucket map */ - SyBigEndianUnpack64(zRaw,&pMap->iNext); - zRaw += 8; - /* Total number of records in the bucket map (This page only) */ - SyBigEndianUnpack32(zRaw,&pMap->nRec); - zRaw += 4; - pMap->iPtr = (sxu16)(zRaw - pHeader->zData); - /* Load the map in memory */ - rc = lhMapLoadPage(pEngine,pMap,pHeader->zData); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Load the bucket map chain if any */ - for(;;){ - pgno iNext = pMap->iNext; - unqlite_page *pPage; - if( iNext == 0 ){ - /* No more map pages */ - break; - } - /* Point to the target page */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iNext,&pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Fill in the structure */ - pMap->iNum = iNext; - pMap->iPtr = 0; - /* Load the map in memory */ - rc = lhMapLoadPage(pEngine,pMap,pPage->zData); - if( rc != UNQLITE_OK ){ - return rc; - } - } - /* All done */ - return UNQLITE_OK; -} -/* - * Perform a record lookup. - */ -static int lhRecordLookup( - lhash_kv_engine *pEngine, /* KV storage engine */ - const void *pKey, /* Lookup key */ - sxu32 nByte, /* Key length */ - lhcell **ppCell /* OUT: Target cell on success */ - ) -{ - lhash_bmap_rec *pRec; - lhpage *pPage; - lhcell *pCell; - pgno iBucket; - sxu32 nHash; - int rc; - /* Acquire the first page (hash Header) so that everything gets loaded autmatically */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Compute the hash of the key first */ - nHash = pEngine->xHash(pKey,nByte); - /* Extract the logical (i.e. not real) page number */ - iBucket = nHash & (pEngine->nmax_split_nucket - 1); - if( iBucket >= (pEngine->split_bucket + pEngine->max_split_bucket) ){ - /* Low mask */ - iBucket = nHash & (pEngine->max_split_bucket - 1); - } - /* Map the logical bucket number to real page number */ - pRec = lhMapFindBucket(pEngine,iBucket); - if( pRec == 0 ){ - /* No such entry */ - return UNQLITE_NOTFOUND; - } - /* Load the master page and it's slave page in-memory */ - rc = lhLoadPage(pEngine,pRec->iReal,0,&pPage,0); - if( rc != UNQLITE_OK ){ - /* IO error, unlikely scenario */ - return rc; - } - /* Lookup for the cell */ - pCell = lhFindCell(pPage,pKey,nByte,nHash); - if( pCell == 0 ){ - /* No such entry */ - return UNQLITE_NOTFOUND; - } - if( ppCell ){ - *ppCell = pCell; - } - return UNQLITE_OK; -} -/* - * Acquire a new page either from the free list or ask the pager - * for a new one. - */ -static int lhAcquirePage(lhash_kv_engine *pEngine,unqlite_page **ppOut) -{ - unqlite_page *pPage; - int rc; - if( pEngine->nFreeList != 0 ){ - /* Acquire one from the free list */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pEngine->nFreeList,&pPage); - if( rc == UNQLITE_OK ){ - /* Point to the next free page */ - SyBigEndianUnpack64(pPage->zData,&pEngine->nFreeList); - /* Update the database header */ - rc = pEngine->pIo->xWrite(pEngine->pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/],pEngine->nFreeList); - /* Tell the pager do not journal this page */ - pEngine->pIo->xDontJournal(pPage); - /* Return to the caller */ - *ppOut = pPage; - /* All done */ - return UNQLITE_OK; - } - } - /* Acquire a new page */ - rc = pEngine->pIo->xNew(pEngine->pIo->pHandle,&pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Point to the target page */ - *ppOut = pPage; - return UNQLITE_OK; -} -/* - * Write a bucket map record to disk. - */ -static int lhMapWriteRecord(lhash_kv_engine *pEngine,pgno iLogic,pgno iReal) -{ - lhash_bmap_page *pMap = &pEngine->sPageMap; - unqlite_page *pPage = 0; - int rc; - if( pMap->iPtr > (pEngine->iPageSize - 16) /* 8 byte logical bucket number + 8 byte real bucket number */ ){ - unqlite_page *pOld; - /* Point to the old page */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pMap->iNum,&pOld); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Acquire a new page */ - rc = lhAcquirePage(pEngine,&pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Reflect the change */ - pMap->iNext = 0; - pMap->iNum = pPage->pgno; - pMap->nRec = 0; - pMap->iPtr = 8/* Next page number */+4/* Total records in the map*/; - /* Link this page */ - rc = pEngine->pIo->xWrite(pOld); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pOld->pgno == pEngine->pHeader->pgno ){ - /* First page (Hash header) */ - SyBigEndianPack64(&pOld->zData[4/*magic*/+4/*hash*/+8/* Free page */+8/*current split bucket*/+8/*Maximum split bucket*/],pPage->pgno); - }else{ - /* Link the new page */ - SyBigEndianPack64(pOld->zData,pPage->pgno); - /* Unref */ - pEngine->pIo->xPageUnref(pOld); - } - /* Assume the last bucket map page */ - rc = pEngine->pIo->xWrite(pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - SyBigEndianPack64(pPage->zData,0); /* Next bucket map page on the list */ - } - if( pPage == 0){ - /* Point to the current map page */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pMap->iNum,&pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - } - /* Make page writable */ - rc = pEngine->pIo->xWrite(pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Write the data */ - SyBigEndianPack64(&pPage->zData[pMap->iPtr],iLogic); - pMap->iPtr += 8; - SyBigEndianPack64(&pPage->zData[pMap->iPtr],iReal); - pMap->iPtr += 8; - /* Install the bucket map */ - rc = lhMapInstallBucket(pEngine,iLogic,iReal); - if( rc == UNQLITE_OK ){ - /* Total number of records */ - pMap->nRec++; - if( pPage->pgno == pEngine->pHeader->pgno ){ - /* Page one: Always writable */ - SyBigEndianPack32( - &pPage->zData[4/*magic*/+4/*hash*/+8/* Free page */+8/*current split bucket*/+8/*Maximum split bucket*/+8/*Next map page*/], - pMap->nRec); - }else{ - /* Make page writable */ - rc = pEngine->pIo->xWrite(pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - SyBigEndianPack32(&pPage->zData[8],pMap->nRec); - } - } - return rc; -} -/* - * Defragment a page. - */ -static int lhPageDefragment(lhpage *pPage) -{ - lhash_kv_engine *pEngine = pPage->pHash; - unsigned char *zTmp,*zPtr,*zEnd,*zPayload; - lhcell *pCell; - /* Get a temporary page from the pager. This opertaion never fail */ - zTmp = pEngine->pIo->xTmpPage(pEngine->pIo->pHandle); - /* Move the target cells to the begining */ - pCell = pPage->pList; - /* Write the slave page number */ - SyBigEndianPack64(&zTmp[2/*Offset of the first cell */+2/*Offset of the first free block */],pPage->sHdr.iSlave); - zPtr = &zTmp[L_HASH_PAGE_HDR_SZ]; /* Offset to start writing from */ - zEnd = &zTmp[pEngine->iPageSize]; - pPage->sHdr.iOfft = 0; /* Offset of the first cell */ - for(;;){ - if( pCell == 0 ){ - /* No more cells */ - break; - } - if( pCell->pPage->pRaw->pgno == pPage->pRaw->pgno ){ - /* Cell payload if locally stored */ - zPayload = 0; - if( pCell->iOvfl == 0 ){ - zPayload = &pCell->pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ]; - } - /* Move the cell */ - pCell->iNext = pPage->sHdr.iOfft; - pCell->iStart = (sxu16)(zPtr - zTmp); /* Offset where this cell start */ - pPage->sHdr.iOfft = pCell->iStart; - /* Write the cell header */ - /* 4 byte hash number */ - SyBigEndianPack32(zPtr,pCell->nHash); - zPtr += 4; - /* 4 byte ley length */ - SyBigEndianPack32(zPtr,pCell->nKey); - zPtr += 4; - /* 8 byte data length */ - SyBigEndianPack64(zPtr,pCell->nData); - zPtr += 8; - /* 2 byte offset of the next cell */ - SyBigEndianPack16(zPtr,pCell->iNext); - zPtr += 2; - /* 8 byte overflow page number */ - SyBigEndianPack64(zPtr,pCell->iOvfl); - zPtr += 8; - if( zPayload ){ - /* Local payload */ - SyMemcpy((const void *)zPayload,zPtr,(sxu32)(pCell->nKey + pCell->nData)); - zPtr += pCell->nKey + pCell->nData; - } - if( zPtr >= zEnd ){ - /* Can't happen */ - break; - } - } - /* Point to the next page */ - pCell = pCell->pNext; - } - /* Mark the free block */ - pPage->nFree = (sxu16)(zEnd - zPtr); /* Block length */ - if( pPage->nFree > 3 ){ - pPage->sHdr.iFree = (sxu16)(zPtr - zTmp); /* Offset of the free block */ - /* Mark the block */ - SyBigEndianPack16(zPtr,0); /* Offset of the next free block */ - SyBigEndianPack16(&zPtr[2],pPage->nFree); /* Block length */ - }else{ - /* Block of length less than 4 bytes are simply discarded */ - pPage->nFree = 0; - pPage->sHdr.iFree = 0; - } - /* Reflect the change */ - SyBigEndianPack16(zTmp,pPage->sHdr.iOfft); /* Offset of the first cell */ - SyBigEndianPack16(&zTmp[2],pPage->sHdr.iFree); /* Offset of the first free block */ - SyMemcpy((const void *)zTmp,pPage->pRaw->zData,pEngine->iPageSize); - /* All done */ - return UNQLITE_OK; -} -/* -** Allocate nByte bytes of space on a page. -** -** Return the index into pPage->pRaw->zData[] of the first byte of -** the new allocation. Or return 0 if there is not enough free -** space on the page to satisfy the allocation request. -** -** If the page contains nBytes of free space but does not contain -** nBytes of contiguous free space, then this routine automatically -** calls defragementPage() to consolidate all free space before -** allocating the new chunk. -*/ -static int lhAllocateSpace(lhpage *pPage,sxu64 nAmount,sxu16 *pOfft) -{ - const unsigned char *zEnd,*zPtr; - sxu16 iNext,iBlksz,nByte; - unsigned char *zPrev; - int rc; - if( (sxu64)pPage->nFree < nAmount ){ - /* Don't bother looking for a free chunk */ - return UNQLITE_FULL; - } - if( pPage->nCell < 10 && ((int)nAmount >= (pPage->pHash->iPageSize / 2)) ){ - /* Big chunk need an overflow page for its data */ - return UNQLITE_FULL; - } - zPtr = &pPage->pRaw->zData[pPage->sHdr.iFree]; - zEnd = &pPage->pRaw->zData[pPage->pHash->iPageSize]; - nByte = (sxu16)nAmount; - zPrev = 0; - iBlksz = 0; /* cc warning */ - /* Perform the lookup */ - for(;;){ - if( zPtr >= zEnd ){ - return UNQLITE_FULL; - } - /* Offset of the next free block */ - SyBigEndianUnpack16(zPtr,&iNext); - /* Block size */ - SyBigEndianUnpack16(&zPtr[2],&iBlksz); - if( iBlksz >= nByte ){ - /* Got one */ - break; - } - zPrev = (unsigned char *)zPtr; - if( iNext == 0 ){ - /* No more free blocks, defragment the page */ - rc = lhPageDefragment(pPage); - if( rc == UNQLITE_OK && pPage->nFree >= nByte) { - /* Free blocks are merged together */ - iNext = 0; - zPtr = &pPage->pRaw->zData[pPage->sHdr.iFree]; - iBlksz = pPage->nFree; - zPrev = 0; - break; - }else{ - return UNQLITE_FULL; - } - } - /* Point to the next free block */ - zPtr = &pPage->pRaw->zData[iNext]; - } - /* Acquire writer lock on this page */ - rc = pPage->pHash->pIo->xWrite(pPage->pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Save block offset */ - *pOfft = (sxu16)(zPtr - pPage->pRaw->zData); - /* Fix pointers */ - if( iBlksz >= nByte && (iBlksz - nByte) > 3 ){ - unsigned char *zBlock = &pPage->pRaw->zData[(*pOfft) + nByte]; - /* Create a new block */ - zPtr = zBlock; - SyBigEndianPack16(zBlock,iNext); /* Offset of the next block */ - SyBigEndianPack16(&zBlock[2],iBlksz-nByte); /* Block size*/ - /* Offset of the new block */ - iNext = (sxu16)(zPtr - pPage->pRaw->zData); - iBlksz = nByte; - } - /* Fix offsets */ - if( zPrev ){ - SyBigEndianPack16(zPrev,iNext); - }else{ - /* First block */ - pPage->sHdr.iFree = iNext; - /* Reflect on the page header */ - SyBigEndianPack16(&pPage->pRaw->zData[2/* Offset of the first cell1*/],iNext); - } - /* All done */ - pPage->nFree -= iBlksz; - return UNQLITE_OK; -} -/* - * Write the cell header into the corresponding offset. - */ -static int lhCellWriteHeader(lhcell *pCell) -{ - lhpage *pPage = pCell->pPage; - unsigned char *zRaw = pPage->pRaw->zData; - /* Seek to the desired location */ - zRaw += pCell->iStart; - /* 4 byte hash number */ - SyBigEndianPack32(zRaw,pCell->nHash); - zRaw += 4; - /* 4 byte key length */ - SyBigEndianPack32(zRaw,pCell->nKey); - zRaw += 4; - /* 8 byte data length */ - SyBigEndianPack64(zRaw,pCell->nData); - zRaw += 8; - /* 2 byte offset of the next cell */ - pCell->iNext = pPage->sHdr.iOfft; - SyBigEndianPack16(zRaw,pCell->iNext); - zRaw += 2; - /* 8 byte overflow page number */ - SyBigEndianPack64(zRaw,pCell->iOvfl); - /* Update the page header */ - pPage->sHdr.iOfft = pCell->iStart; - /* pEngine->pIo->xWrite() has been successfully called on this page */ - SyBigEndianPack16(pPage->pRaw->zData,pCell->iStart); - /* All done */ - return UNQLITE_OK; -} -/* - * Write local payload. - */ -static int lhCellWriteLocalPayload(lhcell *pCell, - const void *pKey,sxu32 nKeylen, - const void *pData,unqlite_int64 nDatalen - ) -{ - /* A writer lock have been acquired on this page */ - lhpage *pPage = pCell->pPage; - unsigned char *zRaw = pPage->pRaw->zData; - /* Seek to the desired location */ - zRaw += pCell->iStart + L_HASH_CELL_SZ; - /* Write the key */ - SyMemcpy(pKey,(void *)zRaw,nKeylen); - zRaw += nKeylen; - if( nDatalen > 0 ){ - /* Write the Data */ - SyMemcpy(pData,(void *)zRaw,(sxu32)nDatalen); - } - return UNQLITE_OK; -} -/* - * Allocate as much overflow page we need to store the cell payload. - */ -static int lhCellWriteOvflPayload(lhcell *pCell,const void *pKey,sxu32 nKeylen,...) -{ - lhpage *pPage = pCell->pPage; - lhash_kv_engine *pEngine = pPage->pHash; - unqlite_page *pOvfl,*pFirst,*pNew; - const unsigned char *zPtr,*zEnd; - unsigned char *zRaw,*zRawEnd; - sxu32 nAvail; - va_list ap; - int rc; - /* Acquire a new overflow page */ - rc = lhAcquirePage(pEngine,&pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Acquire a writer lock */ - rc = pEngine->pIo->xWrite(pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - pFirst = pOvfl; - /* Link */ - pCell->iOvfl = pOvfl->pgno; - /* Update the cell header */ - SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4/*Hash*/ + 4/*Key*/ + 8/*Data*/ + 2 /*Next cell*/],pCell->iOvfl); - /* Start the write process */ - zPtr = (const unsigned char *)pKey; - zEnd = &zPtr[nKeylen]; - SyBigEndianPack64(pOvfl->zData,0); /* Next overflow page on the chain */ - zRaw = &pOvfl->zData[8/* Next ovfl page*/ + 8 /* Data page */ + 2 /* Data offset*/]; - zRawEnd = &pOvfl->zData[pEngine->iPageSize]; - pNew = pOvfl; - /* Write the key */ - for(;;){ - if( zPtr >= zEnd ){ - break; - } - if( zRaw >= zRawEnd ){ - /* Acquire a new page */ - rc = lhAcquirePage(pEngine,&pNew); - if( rc != UNQLITE_OK ){ - return rc; - } - rc = pEngine->pIo->xWrite(pNew); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Link */ - SyBigEndianPack64(pOvfl->zData,pNew->pgno); - pEngine->pIo->xPageUnref(pOvfl); - SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */ - pOvfl = pNew; - zRaw = &pNew->zData[8]; - zRawEnd = &pNew->zData[pEngine->iPageSize]; - } - nAvail = (sxu32)(zRawEnd-zRaw); - nKeylen = (sxu32)(zEnd-zPtr); - if( nKeylen > nAvail ){ - nKeylen = nAvail; - } - SyMemcpy((const void *)zPtr,(void *)zRaw,nKeylen); - /* Synchronize pointers */ - zPtr += nKeylen; - zRaw += nKeylen; - } - rc = UNQLITE_OK; - va_start(ap,nKeylen); - pCell->iDataPage = pNew->pgno; - pCell->iDataOfft = (sxu16)(zRaw-pNew->zData); - /* Write the data page and its offset */ - SyBigEndianPack64(&pFirst->zData[8/*Next ovfl*/],pCell->iDataPage); - SyBigEndianPack16(&pFirst->zData[8/*Next ovfl*/+8/*Data page*/],pCell->iDataOfft); - /* Write data */ - for(;;){ - const void *pData; - sxu32 nDatalen; - sxu64 nData; - pData = va_arg(ap,const void *); - nData = va_arg(ap,sxu64); - if( pData == 0 ){ - /* No more chunks */ - break; - } - /* Write this chunk */ - zPtr = (const unsigned char *)pData; - zEnd = &zPtr[nData]; - for(;;){ - if( zPtr >= zEnd ){ - break; - } - if( zRaw >= zRawEnd ){ - /* Acquire a new page */ - rc = lhAcquirePage(pEngine,&pNew); - if( rc != UNQLITE_OK ){ - va_end(ap); - return rc; - } - rc = pEngine->pIo->xWrite(pNew); - if( rc != UNQLITE_OK ){ - va_end(ap); - return rc; - } - /* Link */ - SyBigEndianPack64(pOvfl->zData,pNew->pgno); - pEngine->pIo->xPageUnref(pOvfl); - SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */ - pOvfl = pNew; - zRaw = &pNew->zData[8]; - zRawEnd = &pNew->zData[pEngine->iPageSize]; - } - nAvail = (sxu32)(zRawEnd-zRaw); - nDatalen = (sxu32)(zEnd-zPtr); - if( nDatalen > nAvail ){ - nDatalen = nAvail; - } - SyMemcpy((const void *)zPtr,(void *)zRaw,nDatalen); - /* Synchronize pointers */ - zPtr += nDatalen; - zRaw += nDatalen; - } - } - /* Unref the overflow page */ - pEngine->pIo->xPageUnref(pOvfl); - va_end(ap); - return UNQLITE_OK; -} -/* - * Restore a page to the free list. - */ -static int lhRestorePage(lhash_kv_engine *pEngine,unqlite_page *pPage) -{ - int rc; - rc = pEngine->pIo->xWrite(pEngine->pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - rc = pEngine->pIo->xWrite(pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Link to the list of free page */ - SyBigEndianPack64(pPage->zData,pEngine->nFreeList); - pEngine->nFreeList = pPage->pgno; - SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/],pEngine->nFreeList); - /* All done */ - return UNQLITE_OK; -} -/* - * Restore cell space and mark it as a free block. - */ -static int lhRestoreSpace(lhpage *pPage,sxu16 iOfft,sxu16 nByte) -{ - unsigned char *zRaw; - if( nByte < 4 ){ - /* At least 4 bytes of freespace must form a valid block */ - return UNQLITE_OK; - } - /* pEngine->pIo->xWrite() has been successfully called on this page */ - zRaw = &pPage->pRaw->zData[iOfft]; - /* Mark as a free block */ - SyBigEndianPack16(zRaw,pPage->sHdr.iFree); /* Offset of the next free block */ - zRaw += 2; - SyBigEndianPack16(zRaw,nByte); - /* Link */ - SyBigEndianPack16(&pPage->pRaw->zData[2/* offset of the first cell */],iOfft); - pPage->sHdr.iFree = iOfft; - pPage->nFree += nByte; - return UNQLITE_OK; -} -/* Forward declaration */ -static lhcell * lhFindSibeling(lhcell *pCell); -/* - * Unlink a cell. - */ -static int lhUnlinkCell(lhcell *pCell) -{ - lhash_kv_engine *pEngine = pCell->pPage->pHash; - lhpage *pPage = pCell->pPage; - sxu16 nByte = L_HASH_CELL_SZ; - lhcell *pPrev; - int rc; - rc = pEngine->pIo->xWrite(pPage->pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Bring the link */ - pPrev = lhFindSibeling(pCell); - if( pPrev ){ - pPrev->iNext = pCell->iNext; - /* Fix offsets in the page header */ - SyBigEndianPack16(&pPage->pRaw->zData[pPrev->iStart + 4/*Hash*/+4/*Key*/+8/*Data*/],pCell->iNext); - }else{ - /* First entry on this page (either master or slave) */ - pPage->sHdr.iOfft = pCell->iNext; - /* Update the page header */ - SyBigEndianPack16(pPage->pRaw->zData,pCell->iNext); - } - /* Restore cell space */ - if( pCell->iOvfl == 0 ){ - nByte += (sxu16)(pCell->nData + pCell->nKey); - } - lhRestoreSpace(pPage,pCell->iStart,nByte); - /* Discard the cell from the in-memory hashtable */ - lhCellDiscard(pCell); - return UNQLITE_OK; -} -/* - * Remove a cell and its paylod (key + data). - */ -static int lhRecordRemove(lhcell *pCell) -{ - lhash_kv_engine *pEngine = pCell->pPage->pHash; - int rc; - if( pCell->iOvfl > 0){ - /* Discard overflow pages */ - unqlite_page *pOvfl; - pgno iNext = pCell->iOvfl; - for(;;){ - /* Point to the overflow page */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iNext,&pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Next page on the chain */ - SyBigEndianUnpack64(pOvfl->zData,&iNext); - /* Restore the page to the free list */ - rc = lhRestorePage(pEngine,pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Unref */ - pEngine->pIo->xPageUnref(pOvfl); - if( iNext == 0 ){ - break; - } - } - } - /* Unlink the cell */ - rc = lhUnlinkCell(pCell); - return rc; -} -/* - * Find cell sibeling. - */ -static lhcell * lhFindSibeling(lhcell *pCell) -{ - lhpage *pPage = pCell->pPage->pMaster; - lhcell *pEntry; - pEntry = pPage->pFirst; - while( pEntry ){ - if( pEntry->pPage == pCell->pPage && pEntry->iNext == pCell->iStart ){ - /* Sibeling found */ - return pEntry; - } - /* Point to the previous entry */ - pEntry = pEntry->pPrev; - } - /* Last inserted cell */ - return 0; -} -/* - * Move a cell to a new location with its new data. - */ -static int lhMoveLocalCell( - lhcell *pCell, - sxu16 iOfft, - const void *pData, - unqlite_int64 nData - ) -{ - sxu16 iKeyOfft = pCell->iStart + L_HASH_CELL_SZ; - lhpage *pPage = pCell->pPage; - lhcell *pSibeling; - pSibeling = lhFindSibeling(pCell); - if( pSibeling ){ - /* Fix link */ - SyBigEndianPack16(&pPage->pRaw->zData[pSibeling->iStart + 4/*Hash*/+4/*Key*/+8/*Data*/],pCell->iNext); - pSibeling->iNext = pCell->iNext; - }else{ - /* First cell, update page header only */ - SyBigEndianPack16(pPage->pRaw->zData,pCell->iNext); - pPage->sHdr.iOfft = pCell->iNext; - } - /* Set the new offset */ - pCell->iStart = iOfft; - pCell->nData = (sxu64)nData; - /* Write the cell payload */ - lhCellWriteLocalPayload(pCell,(const void *)&pPage->pRaw->zData[iKeyOfft],pCell->nKey,pData,nData); - /* Finally write the cell header */ - lhCellWriteHeader(pCell); - /* All done */ - return UNQLITE_OK; -} -/* - * Overwrite an existing record. - */ -static int lhRecordOverwrite( - lhcell *pCell, - const void *pData,unqlite_int64 nByte - ) -{ - lhash_kv_engine *pEngine = pCell->pPage->pHash; - unsigned char *zRaw,*zRawEnd,*zPayload; - const unsigned char *zPtr,*zEnd; - unqlite_page *pOvfl,*pOld,*pNew; - lhpage *pPage = pCell->pPage; - sxu32 nAvail; - pgno iOvfl; - int rc; - /* Acquire a writer lock on this page */ - rc = pEngine->pIo->xWrite(pPage->pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pCell->iOvfl == 0 ){ - /* Local payload, try to deal with the free space issues */ - zPayload = &pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ + pCell->nKey]; - if( pCell->nData == (sxu64)nByte ){ - /* Best scenario, simply a memcpy operation */ - SyMemcpy(pData,(void *)zPayload,(sxu32)nByte); - }else if( (sxu64)nByte < pCell->nData ){ - /* Shorter data, not so ugly */ - SyMemcpy(pData,(void *)zPayload,(sxu32)nByte); - /* Update the cell header */ - SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],nByte); - /* Restore freespace */ - lhRestoreSpace(pPage,(sxu16)(pCell->iStart + L_HASH_CELL_SZ + pCell->nKey + nByte),(sxu16)(pCell->nData - nByte)); - /* New data size */ - pCell->nData = (sxu64)nByte; - }else{ - sxu16 iOfft = 0; /* cc warning */ - /* Check if another chunk is available for this cell */ - rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ + pCell->nKey + nByte,&iOfft); - if( rc != UNQLITE_OK ){ - /* Transfer the payload to an overflow page */ - rc = lhCellWriteOvflPayload(pCell,&pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ],pCell->nKey,pData,nByte,(const void *)0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Update the cell header */ - SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],(sxu64)nByte); - /* Restore freespace */ - lhRestoreSpace(pPage,(sxu16)(pCell->iStart + L_HASH_CELL_SZ),(sxu16)(pCell->nKey + pCell->nData)); - /* New data size */ - pCell->nData = (sxu64)nByte; - }else{ - sxu16 iOldOfft = pCell->iStart; - sxu32 iOld = (sxu32)pCell->nData; - /* Space is available, transfer the cell */ - lhMoveLocalCell(pCell,iOfft,pData,nByte); - /* Restore cell space */ - lhRestoreSpace(pPage,iOldOfft,(sxu16)(L_HASH_CELL_SZ + pCell->nKey + iOld)); - } - } - return UNQLITE_OK; - } - /* Point to the overflow page */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pCell->iDataPage,&pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Relase all old overflow pages first */ - SyBigEndianUnpack64(pOvfl->zData,&iOvfl); - pOld = pOvfl; - for(;;){ - if( iOvfl == 0 ){ - /* No more overflow pages on the chain */ - break; - } - /* Point to the target page */ - if( UNQLITE_OK != pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pOld) ){ - /* Not so fatal if something goes wrong here */ - break; - } - /* Next overflow page to be released */ - SyBigEndianUnpack64(pOld->zData,&iOvfl); - if( pOld != pOvfl ){ /* xx: chm is maniac */ - /* Restore the page to the free list */ - lhRestorePage(pEngine,pOld); - /* Unref */ - pEngine->pIo->xPageUnref(pOld); - } - } - /* Point to the data offset */ - zRaw = &pOvfl->zData[pCell->iDataOfft]; - zRawEnd = &pOvfl->zData[pEngine->iPageSize]; - /* The data to be stored */ - zPtr = (const unsigned char *)pData; - zEnd = &zPtr[nByte]; - /* Start the overwrite process */ - /* Acquire a writer lock */ - rc = pEngine->pIo->xWrite(pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - SyBigEndianPack64(pOvfl->zData,0); - for(;;){ - sxu32 nLen; - if( zPtr >= zEnd ){ - break; - } - if( zRaw >= zRawEnd ){ - /* Acquire a new page */ - rc = lhAcquirePage(pEngine,&pNew); - if( rc != UNQLITE_OK ){ - return rc; - } - rc = pEngine->pIo->xWrite(pNew); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Link */ - SyBigEndianPack64(pOvfl->zData,pNew->pgno); - pEngine->pIo->xPageUnref(pOvfl); - SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */ - pOvfl = pNew; - zRaw = &pNew->zData[8]; - zRawEnd = &pNew->zData[pEngine->iPageSize]; - } - nAvail = (sxu32)(zRawEnd-zRaw); - nLen = (sxu32)(zEnd-zPtr); - if( nLen > nAvail ){ - nLen = nAvail; - } - SyMemcpy((const void *)zPtr,(void *)zRaw,nLen); - /* Synchronize pointers */ - zPtr += nLen; - zRaw += nLen; - } - /* Unref the last overflow page */ - pEngine->pIo->xPageUnref(pOvfl); - /* Finally, update the cell header */ - pCell->nData = (sxu64)nByte; - SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],pCell->nData); - /* All done */ - return UNQLITE_OK; -} -/* - * Append data to an existing record. - */ -static int lhRecordAppend( - lhcell *pCell, - const void *pData,unqlite_int64 nByte - ) -{ - lhash_kv_engine *pEngine = pCell->pPage->pHash; - const unsigned char *zPtr,*zEnd; - lhpage *pPage = pCell->pPage; - unsigned char *zRaw,*zRawEnd; - unqlite_page *pOvfl,*pNew; - sxu64 nDatalen; - sxu32 nAvail; - pgno iOvfl; - int rc; - if( pCell->nData + nByte < pCell->nData ){ - /* Overflow */ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"Append operation will cause data overflow"); - return UNQLITE_LIMIT; - } - /* Acquire a writer lock on this page */ - rc = pEngine->pIo->xWrite(pPage->pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pCell->iOvfl == 0 ){ - sxu16 iOfft = 0; /* cc warning */ - /* Local payload, check for a bigger place */ - rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ + pCell->nKey + pCell->nData + nByte,&iOfft); - if( rc != UNQLITE_OK ){ - /* Transfer the payload to an overflow page */ - rc = lhCellWriteOvflPayload(pCell, - &pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ],pCell->nKey, - (const void *)&pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ + pCell->nKey],pCell->nData, - pData,nByte, - (const void *)0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Update the cell header */ - SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],pCell->nData + nByte); - /* Restore freespace */ - lhRestoreSpace(pPage,(sxu16)(pCell->iStart + L_HASH_CELL_SZ),(sxu16)(pCell->nKey + pCell->nData)); - /* New data size */ - pCell->nData += nByte; - }else{ - sxu16 iOldOfft = pCell->iStart; - sxu32 iOld = (sxu32)pCell->nData; - SyBlob sWorker; - SyBlobInit(&sWorker,&pEngine->sAllocator); - /* Copy the old data */ - rc = SyBlobAppend(&sWorker,(const void *)&pPage->pRaw->zData[pCell->iStart + L_HASH_CELL_SZ + pCell->nKey],(sxu32)pCell->nData); - if( rc == SXRET_OK ){ - /* Append the new data */ - rc = SyBlobAppend(&sWorker,pData,(sxu32)nByte); - } - if( rc != UNQLITE_OK ){ - SyBlobRelease(&sWorker); - return rc; - } - /* Space is available, transfer the cell */ - lhMoveLocalCell(pCell,iOfft,SyBlobData(&sWorker),(unqlite_int64)SyBlobLength(&sWorker)); - /* Restore cell space */ - lhRestoreSpace(pPage,iOldOfft,(sxu16)(L_HASH_CELL_SZ + pCell->nKey + iOld)); - /* All done */ - SyBlobRelease(&sWorker); - } - return UNQLITE_OK; - } - /* Point to the overflow page which hold the data */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,pCell->iDataPage,&pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Next overflow page in the chain */ - SyBigEndianUnpack64(pOvfl->zData,&iOvfl); - /* Point to the end of the chunk */ - zRaw = &pOvfl->zData[pCell->iDataOfft]; - zRawEnd = &pOvfl->zData[pEngine->iPageSize]; - nDatalen = pCell->nData; - nAvail = (sxu32)(zRawEnd - zRaw); - for(;;){ - if( zRaw >= zRawEnd ){ - if( iOvfl == 0 ){ - /* Cant happen */ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"Corrupt overflow page"); - return UNQLITE_CORRUPT; - } - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,iOvfl,&pNew); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Next overflow page on the chain */ - SyBigEndianUnpack64(pNew->zData,&iOvfl); - /* Unref the previous overflow page */ - pEngine->pIo->xPageUnref(pOvfl); - /* Point to the new chunk */ - zRaw = &pNew->zData[8]; - zRawEnd = &pNew->zData[pCell->pPage->pHash->iPageSize]; - nAvail = L_HASH_OVERFLOW_SIZE(pCell->pPage->pHash->iPageSize); - pOvfl = pNew; - } - if( (sxu64)nAvail > nDatalen ){ - zRaw += nDatalen; - break; - }else{ - nDatalen -= nAvail; - } - zRaw += nAvail; - } - /* Start the append process */ - zPtr = (const unsigned char *)pData; - zEnd = &zPtr[nByte]; - /* Acquire a writer lock */ - rc = pEngine->pIo->xWrite(pOvfl); - if( rc != UNQLITE_OK ){ - return rc; - } - for(;;){ - sxu32 nLen; - if( zPtr >= zEnd ){ - break; - } - if( zRaw >= zRawEnd ){ - /* Acquire a new page */ - rc = lhAcquirePage(pEngine,&pNew); - if( rc != UNQLITE_OK ){ - return rc; - } - rc = pEngine->pIo->xWrite(pNew); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Link */ - SyBigEndianPack64(pOvfl->zData,pNew->pgno); - pEngine->pIo->xPageUnref(pOvfl); - SyBigEndianPack64(pNew->zData,0); /* Next overflow page on the chain */ - pOvfl = pNew; - zRaw = &pNew->zData[8]; - zRawEnd = &pNew->zData[pEngine->iPageSize]; - } - nAvail = (sxu32)(zRawEnd-zRaw); - nLen = (sxu32)(zEnd-zPtr); - if( nLen > nAvail ){ - nLen = nAvail; - } - SyMemcpy((const void *)zPtr,(void *)zRaw,nLen); - /* Synchronize pointers */ - zPtr += nLen; - zRaw += nLen; - } - /* Unref the last overflow page */ - pEngine->pIo->xPageUnref(pOvfl); - /* Finally, update the cell header */ - pCell->nData += nByte; - SyBigEndianPack64(&pPage->pRaw->zData[pCell->iStart + 4 /* Hash */ + 4 /* Key */],pCell->nData); - /* All done */ - return UNQLITE_OK; -} -/* - * A write privilege have been acquired on this page. - * Mark it as an empty page (No cells). - */ -static int lhSetEmptyPage(lhpage *pPage) -{ - unsigned char *zRaw = pPage->pRaw->zData; - lhphdr *pHeader = &pPage->sHdr; - sxu16 nByte; - int rc; - /* Acquire a writer lock */ - rc = pPage->pHash->pIo->xWrite(pPage->pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Offset of the first cell */ - SyBigEndianPack16(zRaw,0); - zRaw += 2; - /* Offset of the first free block */ - pHeader->iFree = L_HASH_PAGE_HDR_SZ; - SyBigEndianPack16(zRaw,L_HASH_PAGE_HDR_SZ); - zRaw += 2; - /* Slave page number */ - SyBigEndianPack64(zRaw,0); - zRaw += 8; - /* Fill the free block */ - SyBigEndianPack16(zRaw,0); /* Offset of the next free block */ - zRaw += 2; - nByte = (sxu16)L_HASH_MX_FREE_SPACE(pPage->pHash->iPageSize); - SyBigEndianPack16(zRaw,nByte); - pPage->nFree = nByte; - /* Do not add this page to the hot dirty list */ - pPage->pHash->pIo->xDontMkHot(pPage->pRaw); - return UNQLITE_OK; -} -/* Forward declaration */ -static int lhSlaveStore( - lhpage *pPage, - const void *pKey,sxu32 nKeyLen, - const void *pData,unqlite_int64 nDataLen, - sxu32 nHash - ); -/* - * Store a cell and its payload in a given page. - */ -static int lhStoreCell( - lhpage *pPage, /* Target page */ - const void *pKey,sxu32 nKeyLen, /* Payload: Key */ - const void *pData,unqlite_int64 nDataLen, /* Payload: Data */ - sxu32 nHash, /* Hash of the key */ - int auto_append /* Auto append a slave page if full */ - ) -{ - lhash_kv_engine *pEngine = pPage->pHash; - int iNeedOvfl = 0; /* Need overflow page for this cell and its payload*/ - lhcell *pCell; - sxu16 nOfft; - int rc; - /* Acquire a writer lock on this page first */ - rc = pEngine->pIo->xWrite(pPage->pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Check for a free block */ - rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ+nKeyLen+nDataLen,&nOfft); - if( rc != UNQLITE_OK ){ - /* Check for a free block to hold a single cell only (without payload) */ - rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ,&nOfft); - if( rc != UNQLITE_OK ){ - if( !auto_append ){ - /* A split must be done */ - return UNQLITE_FULL; - }else{ - /* Store this record in a slave page */ - rc = lhSlaveStore(pPage,pKey,nKeyLen,pData,nDataLen,nHash); - return rc; - } - } - iNeedOvfl = 1; - } - /* Allocate a new cell instance */ - pCell = lhNewCell(pEngine,pPage); - if( pCell == 0 ){ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"KV store is running out of memory"); - return UNQLITE_NOMEM; - } - /* Fill-in the structure */ - pCell->iStart = nOfft; - pCell->nKey = nKeyLen; - pCell->nData = (sxu64)nDataLen; - pCell->nHash = nHash; - if( nKeyLen < 262144 /* 256 KB */ ){ - /* Keep the key in-memory for fast lookup */ - SyBlobAppend(&pCell->sKey,pKey,nKeyLen); - } - /* Link the cell */ - rc = lhInstallCell(pCell); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Write the payload */ - if( iNeedOvfl ){ - rc = lhCellWriteOvflPayload(pCell,pKey,nKeyLen,pData,nDataLen,(const void *)0); - if( rc != UNQLITE_OK ){ - lhCellDiscard(pCell); - return rc; - } - }else{ - lhCellWriteLocalPayload(pCell,pKey,nKeyLen,pData,nDataLen); - } - /* Finally, Write the cell header */ - lhCellWriteHeader(pCell); - /* All done */ - return UNQLITE_OK; -} -/* - * Find a slave page capable of hosting the given amount. - */ -static int lhFindSlavePage(lhpage *pPage,sxu64 nAmount,sxu16 *pOfft,lhpage **ppSlave) -{ - lhash_kv_engine *pEngine = pPage->pHash; - lhpage *pMaster = pPage->pMaster; - lhpage *pSlave = pMaster->pSlave; - unqlite_page *pRaw; - lhpage *pNew; - sxu16 iOfft; - sxi32 i; - int rc; - /* Look for an already attached slave page */ - for( i = 0 ; i < pMaster->iSlave ; ++i ){ - /* Find a free chunk big enough */ - sxu16 size = (sxu16)(L_HASH_CELL_SZ + nAmount); - rc = lhAllocateSpace(pSlave,size,&iOfft); - if( rc != UNQLITE_OK ){ - /* A space for cell header only */ - size = L_HASH_CELL_SZ; - rc = lhAllocateSpace(pSlave,size,&iOfft); - } - if( rc == UNQLITE_OK ){ - /* All done */ - if( pOfft ){ - *pOfft = iOfft; - }else{ - rc = lhRestoreSpace(pSlave, iOfft, size); - } - *ppSlave = pSlave; - return rc; - } - /* Point to the next slave page */ - pSlave = pSlave->pNextSlave; - } - /* Acquire a new slave page */ - rc = lhAcquirePage(pEngine,&pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Last slave page */ - pSlave = pMaster->pSlave; - if( pSlave == 0 ){ - /* First slave page */ - pSlave = pMaster; - } - /* Initialize the page */ - pNew = lhNewPage(pEngine,pRaw,pMaster); - if( pNew == 0 ){ - return UNQLITE_NOMEM; - } - /* Mark as an empty page */ - rc = lhSetEmptyPage(pNew); - if( rc != UNQLITE_OK ){ - goto fail; - } - if( pOfft ){ - /* Look for a free block */ - if( UNQLITE_OK != lhAllocateSpace(pNew,L_HASH_CELL_SZ+nAmount,&iOfft) ){ - /* Cell header only */ - lhAllocateSpace(pNew,L_HASH_CELL_SZ,&iOfft); /* Never fail */ - } - *pOfft = iOfft; - } - /* Link this page to the previous slave page */ - rc = pEngine->pIo->xWrite(pSlave->pRaw); - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Reflect in the page header */ - SyBigEndianPack64(&pSlave->pRaw->zData[2/*Cell offset*/+2/*Free block offset*/],pRaw->pgno); - pSlave->sHdr.iSlave = pRaw->pgno; - /* All done */ - *ppSlave = pNew; - return UNQLITE_OK; -fail: - pEngine->pIo->xPageUnref(pNew->pRaw); /* pNew will be released in this call */ - return rc; - -} -/* - * Perform a store operation in a slave page. - */ -static int lhSlaveStore( - lhpage *pPage, /* Master page */ - const void *pKey,sxu32 nKeyLen, /* Payload: key */ - const void *pData,unqlite_int64 nDataLen, /* Payload: data */ - sxu32 nHash /* Hash of the key */ - ) -{ - lhpage *pSlave; - int rc; - /* Find a slave page */ - rc = lhFindSlavePage(pPage,nKeyLen + nDataLen,0,&pSlave); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Perform the insertion in the slave page */ - rc = lhStoreCell(pSlave,pKey,nKeyLen,pData,nDataLen,nHash,1); - return rc; -} -/* - * Transfer a cell to a new page (either a master or slave). - */ -static int lhTransferCell(lhcell *pTarget,lhpage *pPage) -{ - lhcell *pCell; - sxu16 nOfft; - int rc; - /* Check for a free block to hold a single cell only */ - rc = lhAllocateSpace(pPage,L_HASH_CELL_SZ,&nOfft); - if( rc != UNQLITE_OK ){ - /* Store in a slave page */ - rc = lhFindSlavePage(pPage,L_HASH_CELL_SZ,&nOfft,&pPage); - if( rc != UNQLITE_OK ){ - return rc; - } - } - /* Allocate a new cell instance */ - pCell = lhNewCell(pPage->pHash,pPage); - if( pCell == 0 ){ - return UNQLITE_NOMEM; - } - /* Fill-in the structure */ - pCell->iStart = nOfft; - pCell->nData = pTarget->nData; - pCell->nKey = pTarget->nKey; - pCell->iOvfl = pTarget->iOvfl; - pCell->iDataOfft = pTarget->iDataOfft; - pCell->iDataPage = pTarget->iDataPage; - pCell->nHash = pTarget->nHash; - SyBlobDup(&pTarget->sKey,&pCell->sKey); - /* Link the cell */ - rc = lhInstallCell(pCell); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Finally, Write the cell header */ - lhCellWriteHeader(pCell); - /* All done */ - return UNQLITE_OK; -} -/* - * Perform a page split. - */ -static int lhPageSplit( - lhpage *pOld, /* Page to be split */ - lhpage *pNew, /* New page */ - pgno split_bucket, /* Current split bucket */ - pgno high_mask /* High mask (Max split bucket - 1) */ - ) -{ - lhcell *pCell,*pNext; - SyBlob sWorker; - pgno iBucket; - int rc; - SyBlobInit(&sWorker,&pOld->pHash->sAllocator); - /* Perform the split */ - pCell = pOld->pList; - for( ;; ){ - if( pCell == 0 ){ - /* No more cells */ - break; - } - /* Obtain the new logical bucket */ - iBucket = pCell->nHash & high_mask; - pNext = pCell->pNext; - if( iBucket != split_bucket){ - rc = UNQLITE_OK; - if( pCell->iOvfl ){ - /* Transfer the cell only */ - rc = lhTransferCell(pCell,pNew); - }else{ - /* Transfer the cell and its payload */ - SyBlobReset(&sWorker); - if( SyBlobLength(&pCell->sKey) < 1 ){ - /* Consume the key */ - rc = lhConsumeCellkey(pCell,unqliteDataConsumer,&pCell->sKey,0); - if( rc != UNQLITE_OK ){ - goto fail; - } - } - /* Consume the data (Very small data < 65k) */ - rc = lhConsumeCellData(pCell,unqliteDataConsumer,&sWorker); - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Perform the transfer */ - rc = lhStoreCell( - pNew, - SyBlobData(&pCell->sKey),(int)SyBlobLength(&pCell->sKey), - SyBlobData(&sWorker),SyBlobLength(&sWorker), - pCell->nHash, - 1 - ); - } - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Discard the cell from the old page */ - lhUnlinkCell(pCell); - } - /* Point to the next cell */ - pCell = pNext; - } - /* All done */ - rc = UNQLITE_OK; -fail: - SyBlobRelease(&sWorker); - return rc; -} -/* - * Perform the infamous linear hash split operation. - */ -static int lhSplit(lhpage *pTarget,int *pRetry) -{ - lhash_kv_engine *pEngine = pTarget->pHash; - lhash_bmap_rec *pRec; - lhpage *pOld,*pNew; - unqlite_page *pRaw; - int rc; - /* Get the real page number of the bucket to split */ - pRec = lhMapFindBucket(pEngine,pEngine->split_bucket); - if( pRec == 0 ){ - /* Can't happen */ - return UNQLITE_CORRUPT; - } - /* Load the page to be split */ - rc = lhLoadPage(pEngine,pRec->iReal,0,&pOld,0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Request a new page */ - rc = lhAcquirePage(pEngine,&pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Initialize the page */ - pNew = lhNewPage(pEngine,pRaw,0); - if( pNew == 0 ){ - return UNQLITE_NOMEM; - } - /* Mark as an empty page */ - rc = lhSetEmptyPage(pNew); - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Install and write the logical map record */ - rc = lhMapWriteRecord(pEngine, - pEngine->split_bucket + pEngine->max_split_bucket, - pRaw->pgno - ); - if( rc != UNQLITE_OK ){ - goto fail; - } - if( pTarget->pRaw->pgno == pOld->pRaw->pgno ){ - *pRetry = 1; - } - /* Perform the split */ - rc = lhPageSplit(pOld,pNew,pEngine->split_bucket,pEngine->nmax_split_nucket - 1); - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Update the database header */ - pEngine->split_bucket++; - /* Acquire a writer lock on the first page */ - rc = pEngine->pIo->xWrite(pEngine->pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pEngine->split_bucket >= pEngine->max_split_bucket ){ - /* Increment the generation number */ - pEngine->split_bucket = 0; - pEngine->max_split_bucket = pEngine->nmax_split_nucket; - pEngine->nmax_split_nucket <<= 1; - if( !pEngine->nmax_split_nucket ){ - /* If this happen to your installation, please tell us */ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"Database page (64-bit integer) limit reached"); - return UNQLITE_LIMIT; - } - /* Reflect in the page header */ - SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/+8/*Free list*/],pEngine->split_bucket); - SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/+8/*Free list*/+8/*Split bucket*/],pEngine->max_split_bucket); - }else{ - /* Modify only the split bucket */ - SyBigEndianPack64(&pEngine->pHeader->zData[4/*Magic*/+4/*Hash*/+8/*Free list*/],pEngine->split_bucket); - } - /* All done */ - return UNQLITE_OK; -fail: - pEngine->pIo->xPageUnref(pNew->pRaw); - return rc; -} -/* - * Store a record in the target page. - */ -static int lhRecordInstall( - lhpage *pPage, /* Target page */ - sxu32 nHash, /* Hash of the key */ - const void *pKey,sxu32 nKeyLen, /* Payload: Key */ - const void *pData,unqlite_int64 nDataLen /* Payload: Data */ - ) -{ - int rc; - rc = lhStoreCell(pPage,pKey,nKeyLen,pData,nDataLen,nHash,0); - if( rc == UNQLITE_FULL ){ - int do_retry = 0; - /* Split */ - rc = lhSplit(pPage,&do_retry); - if( rc == UNQLITE_OK ){ - if( do_retry ){ - /* Re-calculate logical bucket number */ - return SXERR_RETRY; - } - /* Perform the store */ - rc = lhStoreCell(pPage,pKey,nKeyLen,pData,nDataLen,nHash,1); - } - } - return rc; -} -/* - * Insert a record (Either overwrite or append operation) in our database. - */ -static int lh_record_insert( - unqlite_kv_engine *pKv, /* KV store */ - const void *pKey,sxu32 nKeyLen, /* Payload: Key */ - const void *pData,unqlite_int64 nDataLen, /* Payload: data */ - int is_append /* True for an append operation */ - ) -{ - lhash_kv_engine *pEngine = (lhash_kv_engine *)pKv; - lhash_bmap_rec *pRec; - unqlite_page *pRaw; - lhpage *pPage; - lhcell *pCell; - pgno iBucket; - sxu32 nHash; - int iCnt; - int rc; - - /* Acquire the first page (DB hash Header) so that everything gets loaded autmatically */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0); - if( rc != UNQLITE_OK ){ - return rc; - } - iCnt = 0; - /* Compute the hash of the key first */ - nHash = pEngine->xHash(pKey,(sxu32)nKeyLen); -retry: - /* Extract the logical bucket number */ - iBucket = nHash & (pEngine->nmax_split_nucket - 1); - if( iBucket >= pEngine->split_bucket + pEngine->max_split_bucket ){ - /* Low mask */ - iBucket = nHash & (pEngine->max_split_bucket - 1); - } - /* Map the logical bucket number to real page number */ - pRec = lhMapFindBucket(pEngine,iBucket); - if( pRec == 0 ){ - /* Request a new page */ - rc = lhAcquirePage(pEngine,&pRaw); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Initialize the page */ - pPage = lhNewPage(pEngine,pRaw,0); - if( pPage == 0 ){ - return UNQLITE_NOMEM; - } - /* Mark as an empty page */ - rc = lhSetEmptyPage(pPage); - if( rc != UNQLITE_OK ){ - pEngine->pIo->xPageUnref(pRaw); /* pPage will be released during this call */ - return rc; - } - /* Store the cell */ - rc = lhStoreCell(pPage,pKey,nKeyLen,pData,nDataLen,nHash,1); - if( rc == UNQLITE_OK ){ - /* Install and write the logical map record */ - rc = lhMapWriteRecord(pEngine,iBucket,pRaw->pgno); - } - pEngine->pIo->xPageUnref(pRaw); - return rc; - }else{ - /* Load the page */ - rc = lhLoadPage(pEngine,pRec->iReal,0,&pPage,0); - if( rc != UNQLITE_OK ){ - /* IO error, unlikely scenario */ - return rc; - } - /* Do not add this page to the hot dirty list */ - pEngine->pIo->xDontMkHot(pPage->pRaw); - /* Lookup for the cell */ - pCell = lhFindCell(pPage,pKey,(sxu32)nKeyLen,nHash); - if( pCell == 0 ){ - /* Create the record */ - rc = lhRecordInstall(pPage,nHash,pKey,nKeyLen,pData,nDataLen); - if( rc == SXERR_RETRY && iCnt++ < 2 ){ - rc = UNQLITE_OK; - goto retry; - } - }else{ - if( is_append ){ - /* Append operation */ - rc = lhRecordAppend(pCell,pData,nDataLen); - }else{ - /* Overwrite old value */ - rc = lhRecordOverwrite(pCell,pData,nDataLen); - } - } - pEngine->pIo->xPageUnref(pPage->pRaw); - } - return rc; -} -/* - * Replace method. - */ -static int lhash_kv_replace( - unqlite_kv_engine *pKv, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ) -{ - int rc; - rc = lh_record_insert(pKv,pKey,(sxu32)nKeyLen,pData,nDataLen,0); - return rc; -} -/* - * Append method. - */ -static int lhash_kv_append( - unqlite_kv_engine *pKv, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ) -{ - int rc; - rc = lh_record_insert(pKv,pKey,(sxu32)nKeyLen,pData,nDataLen,1); - return rc; -} -/* - * Write the hash header (Page one). - */ -static int lhash_write_header(lhash_kv_engine *pEngine,unqlite_page *pHeader) -{ - unsigned char *zRaw = pHeader->zData; - lhash_bmap_page *pMap; - - pEngine->pHeader = pHeader; - /* 4 byte magic number */ - SyBigEndianPack32(zRaw,pEngine->nMagic); - zRaw += 4; - /* 4 byte hash value to identify a valid hash function */ - SyBigEndianPack32(zRaw,pEngine->xHash(L_HASH_WORD,sizeof(L_HASH_WORD)-1)); - zRaw += 4; - /* List of free pages: Empty */ - SyBigEndianPack64(zRaw,0); - zRaw += 8; - /* Current split bucket */ - SyBigEndianPack64(zRaw,pEngine->split_bucket); - zRaw += 8; - /* Maximum split bucket */ - SyBigEndianPack64(zRaw,pEngine->max_split_bucket); - zRaw += 8; - /* Initialiaze the bucket map */ - pMap = &pEngine->sPageMap; - /* Fill in the structure */ - pMap->iNum = pHeader->pgno; - /* Next page in the bucket map */ - SyBigEndianPack64(zRaw,0); - zRaw += 8; - /* Total number of records in the bucket map */ - SyBigEndianPack32(zRaw,0); - zRaw += 4; - pMap->iPtr = (sxu16)(zRaw - pHeader->zData); - /* All done */ - return UNQLITE_OK; - } -/* - * Exported: xOpen() method. - */ -static int lhash_kv_open(unqlite_kv_engine *pEngine,pgno dbSize) -{ - lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine; - unqlite_page *pHeader; - int rc; - if( dbSize < 1 ){ - /* A new database, create the header */ - rc = pEngine->pIo->xNew(pEngine->pIo->pHandle,&pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Acquire a writer lock */ - rc = pEngine->pIo->xWrite(pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Write the hash header */ - rc = lhash_write_header(pHash,pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - }else{ - /* Acquire the page one of the database */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,&pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Read the database header */ - rc = lhash_read_header(pHash,pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - } - return UNQLITE_OK; -} -/* - * Release a master or slave page. (xUnpin callback). - */ -static void lhash_page_release(void *pUserData) -{ - lhpage *pPage = (lhpage *)pUserData; - lhash_kv_engine *pEngine = pPage->pHash; - lhcell *pNext,*pCell = pPage->pList; - unqlite_page *pRaw = pPage->pRaw; - sxu32 n; - /* Drop in-memory cells */ - for( n = 0 ; n < pPage->nCell ; ++n ){ - pNext = pCell->pNext; - SyBlobRelease(&pCell->sKey); - /* Release the cell instance */ - SyMemBackendPoolFree(&pEngine->sAllocator,(void *)pCell); - /* Point to the next entry */ - pCell = pNext; - } - if( pPage->apCell ){ - /* Release the cell table */ - SyMemBackendFree(&pEngine->sAllocator,(void *)pPage->apCell); - } - /* Finally, release the whole page */ - SyMemBackendPoolFree(&pEngine->sAllocator,pPage); - pRaw->pUserData = 0; -} -/* - * Default hash function (DJB). - */ -static sxu32 lhash_bin_hash(const void *pSrc,sxu32 nLen) -{ - register unsigned char *zIn = (unsigned char *)pSrc; - unsigned char *zEnd; - sxu32 nH = 5381; - if( nLen > 2048 /* 2K */ ){ - nLen = 2048; - } - zEnd = &zIn[nLen]; - for(;;){ - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - } - return nH; -} -/* - * Exported: xInit() method. - * Initialize the Key value storage engine. - */ -static int lhash_kv_init(unqlite_kv_engine *pEngine,int iPageSize) -{ - lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine; - int rc; - - /* This structure is always zeroed, go to the initialization directly */ - SyMemBackendInitFromParent(&pHash->sAllocator,unqliteExportMemBackend()); -//#if defined(UNQLITE_ENABLE_THREADS) -// /* Already protected by the upper layers */ -// SyMemBackendDisbaleMutexing(&pHash->sAllocator); -//#endif - pHash->iPageSize = iPageSize; - /* Default hash function */ - pHash->xHash = lhash_bin_hash; - /* Default comparison function */ - pHash->xCmp = SyMemcmp; - /* Allocate a new record map */ - pHash->nBuckSize = 32; - pHash->apMap = (lhash_bmap_rec **)SyMemBackendAlloc(&pHash->sAllocator,pHash->nBuckSize *sizeof(lhash_bmap_rec *)); - if( pHash->apMap == 0 ){ - rc = UNQLITE_NOMEM; - goto err; - } - /* Zero the table */ - SyZero(pHash->apMap,pHash->nBuckSize * sizeof(lhash_bmap_rec *)); - /* Linear hashing components */ - pHash->split_bucket = 0; /* Logical not real bucket number */ - pHash->max_split_bucket = 1; - pHash->nmax_split_nucket = 2; - pHash->nMagic = L_HASH_MAGIC; - /* Install the cache unpin and reload callbacks */ - pHash->pIo->xSetUnpin(pHash->pIo->pHandle,lhash_page_release); - pHash->pIo->xSetReload(pHash->pIo->pHandle,lhash_page_release); - return UNQLITE_OK; -err: - SyMemBackendRelease(&pHash->sAllocator); - return rc; -} -/* - * Exported: xRelease() method. - * Release the Key value storage engine. - */ -static void lhash_kv_release(unqlite_kv_engine *pEngine) -{ - lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine; - /* Release the private memory backend */ - SyMemBackendRelease(&pHash->sAllocator); -} -/* - * Exported: xConfig() method. - * Configure the linear hash KV store. - */ -static int lhash_kv_config(unqlite_kv_engine *pEngine,int op,va_list ap) -{ - lhash_kv_engine *pHash = (lhash_kv_engine *)pEngine; - int rc = UNQLITE_OK; - switch(op){ - case UNQLITE_KV_CONFIG_HASH_FUNC: { - /* Default hash function */ - if( pHash->nBuckRec > 0 ){ - /* Locked operation */ - rc = UNQLITE_LOCKED; - }else{ - ProcHash xHash = va_arg(ap,ProcHash); - if( xHash ){ - pHash->xHash = xHash; - } - } - break; - } - case UNQLITE_KV_CONFIG_CMP_FUNC: { - /* Default comparison function */ - ProcCmp xCmp = va_arg(ap,ProcCmp); - if( xCmp ){ - pHash->xCmp = xCmp; - } - break; - } - default: - /* Unknown OP */ - rc = UNQLITE_UNKNOWN; - break; - } - return rc; -} -/* - * Each public cursor is identified by an instance of this structure. - */ -typedef struct lhash_kv_cursor lhash_kv_cursor; -struct lhash_kv_cursor -{ - unqlite_kv_engine *pStore; /* Must be first */ - /* Private fields */ - int iState; /* Current state of the cursor */ - int is_first; /* True to read the database header */ - lhcell *pCell; /* Current cell we are processing */ - unqlite_page *pRaw; /* Raw disk page */ - lhash_bmap_rec *pRec; /* Logical to real bucket map */ -}; -/* - * Possible state of the cursor - */ -#define L_HASH_CURSOR_STATE_NEXT_PAGE 1 /* Next page in the list */ -#define L_HASH_CURSOR_STATE_CELL 2 /* Processing Cell */ -#define L_HASH_CURSOR_STATE_DONE 3 /* Cursor does not point to anything */ -/* - * Initialize the cursor. - */ -static void lhInitCursor(unqlite_kv_cursor *pPtr) -{ - lhash_kv_engine *pEngine = (lhash_kv_engine *)pPtr->pStore; - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr; - /* Init */ - pCur->iState = L_HASH_CURSOR_STATE_NEXT_PAGE; - pCur->pCell = 0; - pCur->pRec = pEngine->pFirst; - pCur->pRaw = 0; - pCur->is_first = 1; -} -/* - * Point to the next page on the database. - */ -static int lhCursorNextPage(lhash_kv_cursor *pPtr) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr; - lhash_bmap_rec *pRec; - lhpage *pPage; - int rc; - for(;;){ - pRec = pCur->pRec; - if( pRec == 0 ){ - pCur->iState = L_HASH_CURSOR_STATE_DONE; - return UNQLITE_DONE; - } - if( pPtr->iState == L_HASH_CURSOR_STATE_CELL && pPtr->pRaw ){ - /* Unref this page */ - pCur->pStore->pIo->xPageUnref(pPtr->pRaw); - pPtr->pRaw = 0; - } - /* Advance the map cursor */ - pCur->pRec = pRec->pPrev; /* Not a bug, reverse link */ - /* Load the next page on the list */ - rc = lhLoadPage((lhash_kv_engine *)pCur->pStore,pRec->iReal,0,&pPage,0); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pPage->pList ){ - /* Reflect the change */ - pCur->pCell = pPage->pList; - pCur->iState = L_HASH_CURSOR_STATE_CELL; - pCur->pRaw = pPage->pRaw; - break; - } - /* Empty page, discard this page and continue */ - pPage->pHash->pIo->xPageUnref(pPage->pRaw); - } - return UNQLITE_OK; -} -/* - * Point to the previous page on the database. - */ -static int lhCursorPrevPage(lhash_kv_cursor *pPtr) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr; - lhash_bmap_rec *pRec; - lhpage *pPage; - int rc; - for(;;){ - pRec = pCur->pRec; - if( pRec == 0 ){ - pCur->iState = L_HASH_CURSOR_STATE_DONE; - return UNQLITE_DONE; - } - if( pPtr->iState == L_HASH_CURSOR_STATE_CELL && pPtr->pRaw ){ - /* Unref this page */ - pCur->pStore->pIo->xPageUnref(pPtr->pRaw); - pPtr->pRaw = 0; - } - /* Advance the map cursor */ - pCur->pRec = pRec->pNext; /* Not a bug, reverse link */ - /* Load the previous page on the list */ - rc = lhLoadPage((lhash_kv_engine *)pCur->pStore,pRec->iReal,0,&pPage,0); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pPage->pFirst ){ - /* Reflect the change */ - pCur->pCell = pPage->pFirst; - pCur->iState = L_HASH_CURSOR_STATE_CELL; - pCur->pRaw = pPage->pRaw; - break; - } - /* Discard this page and continue */ - pPage->pHash->pIo->xPageUnref(pPage->pRaw); - } - return UNQLITE_OK; -} -/* - * Is a valid cursor. - */ -static int lhCursorValid(unqlite_kv_cursor *pPtr) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pPtr; - return (pCur->iState == L_HASH_CURSOR_STATE_CELL) && pCur->pCell; -} -/* - * Point to the first record. - */ -static int lhCursorFirst(unqlite_kv_cursor *pCursor) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhash_kv_engine *pEngine = (lhash_kv_engine *)pCursor->pStore; - int rc; - if( pCur->is_first ){ - /* Read the database header first */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0); - if( rc != UNQLITE_OK ){ - return rc; - } - pCur->is_first = 0; - } - /* Point to the first map record */ - pCur->pRec = pEngine->pFirst; - /* Load the cells */ - rc = lhCursorNextPage(pCur); - return rc; -} -/* - * Point to the last record. - */ -static int lhCursorLast(unqlite_kv_cursor *pCursor) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhash_kv_engine *pEngine = (lhash_kv_engine *)pCursor->pStore; - int rc; - if( pCur->is_first ){ - /* Read the database header first */ - rc = pEngine->pIo->xGet(pEngine->pIo->pHandle,1,0); - if( rc != UNQLITE_OK ){ - return rc; - } - pCur->is_first = 0; - } - /* Point to the last map record */ - pCur->pRec = pEngine->pList; - /* Load the cells */ - rc = lhCursorPrevPage(pCur); - return rc; -} -/* - * Reset the cursor. - */ -static void lhCursorReset(unqlite_kv_cursor *pCursor) -{ - lhCursorFirst(pCursor); -} -/* - * Point to the next record. - */ -static int lhCursorNext(unqlite_kv_cursor *pCursor) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhcell *pCell; - int rc; - if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){ - /* Load the cells of the next page */ - rc = lhCursorNextPage(pCur); - return rc; - } - pCell = pCur->pCell; - pCur->pCell = pCell->pNext; - if( pCur->pCell == 0 ){ - /* Load the cells of the next page */ - rc = lhCursorNextPage(pCur); - return rc; - } - return UNQLITE_OK; -} -/* - * Point to the previous record. - */ -static int lhCursorPrev(unqlite_kv_cursor *pCursor) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhcell *pCell; - int rc; - if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){ - /* Load the cells of the previous page */ - rc = lhCursorPrevPage(pCur); - return rc; - } - pCell = pCur->pCell; - pCur->pCell = pCell->pPrev; - if( pCur->pCell == 0 ){ - /* Load the cells of the previous page */ - rc = lhCursorPrevPage(pCur); - return rc; - } - return UNQLITE_OK; -} -/* - * Return key length. - */ -static int lhCursorKeyLength(unqlite_kv_cursor *pCursor,int *pLen) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhcell *pCell; - - if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){ - /* Invalid state */ - return UNQLITE_INVALID; - } - /* Point to the target cell */ - pCell = pCur->pCell; - /* Return key length */ - *pLen = (int)pCell->nKey; - return UNQLITE_OK; -} -/* - * Return data length. - */ -static int lhCursorDataLength(unqlite_kv_cursor *pCursor,unqlite_int64 *pLen) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhcell *pCell; - - if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){ - /* Invalid state */ - return UNQLITE_INVALID; - } - /* Point to the target cell */ - pCell = pCur->pCell; - /* Return data length */ - *pLen = (unqlite_int64)pCell->nData; - return UNQLITE_OK; -} -/* - * Consume the key. - */ -static int lhCursorKey(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhcell *pCell; - int rc; - if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){ - /* Invalid state */ - return UNQLITE_INVALID; - } - /* Point to the target cell */ - pCell = pCur->pCell; - if( SyBlobLength(&pCell->sKey) > 0 ){ - /* Consume the key directly */ - rc = xConsumer(SyBlobData(&pCell->sKey),SyBlobLength(&pCell->sKey),pUserData); - }else{ - /* Very large key */ - rc = lhConsumeCellkey(pCell,xConsumer,pUserData,0); - } - return rc; -} -/* - * Consume the data. - */ -static int lhCursorData(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhcell *pCell; - int rc; - if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){ - /* Invalid state */ - return UNQLITE_INVALID; - } - /* Point to the target cell */ - pCell = pCur->pCell; - /* Consume the data */ - rc = lhConsumeCellData(pCell,xConsumer,pUserData); - return rc; -} -/* - * Find a partiuclar record. - */ -static int lhCursorSeek(unqlite_kv_cursor *pCursor,const void *pKey,int nByte,int iPos) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - int rc; - /* Perform a lookup */ - rc = lhRecordLookup((lhash_kv_engine *)pCur->pStore,pKey,nByte,&pCur->pCell); - if( rc != UNQLITE_OK ){ - SXUNUSED(iPos); - pCur->pCell = 0; - pCur->iState = L_HASH_CURSOR_STATE_DONE; - return rc; - } - pCur->iState = L_HASH_CURSOR_STATE_CELL; - return UNQLITE_OK; -} -/* - * Remove a particular record. - */ -static int lhCursorDelete(unqlite_kv_cursor *pCursor) -{ - lhash_kv_cursor *pCur = (lhash_kv_cursor *)pCursor; - lhcell *pCell; - int rc; - if( pCur->iState != L_HASH_CURSOR_STATE_CELL || pCur->pCell == 0 ){ - /* Invalid state */ - return UNQLITE_INVALID; - } - /* Point to the target cell */ - pCell = pCur->pCell; - /* Point to the next entry */ - pCur->pCell = pCell->pNext; - /* Perform the deletion */ - rc = lhRecordRemove(pCell); - return rc; -} -/* - * Export the linear-hash storage engine. - */ -UNQLITE_PRIVATE const unqlite_kv_methods * unqliteExportDiskKvStorage(void) -{ - static const unqlite_kv_methods sDiskStore = { - "hash", /* zName */ - sizeof(lhash_kv_engine), /* szKv */ - sizeof(lhash_kv_cursor), /* szCursor */ - 1, /* iVersion */ - lhash_kv_init, /* xInit */ - lhash_kv_release, /* xRelease */ - lhash_kv_config, /* xConfig */ - lhash_kv_open, /* xOpen */ - lhash_kv_replace, /* xReplace */ - lhash_kv_append, /* xAppend */ - lhInitCursor, /* xCursorInit */ - lhCursorSeek, /* xSeek */ - lhCursorFirst, /* xFirst */ - lhCursorLast, /* xLast */ - lhCursorValid, /* xValid */ - lhCursorNext, /* xNext */ - lhCursorPrev, /* xPrev */ - lhCursorDelete, /* xDelete */ - lhCursorKeyLength, /* xKeyLength */ - lhCursorKey, /* xKey */ - lhCursorDataLength, /* xDataLength */ - lhCursorData, /* xData */ - lhCursorReset, /* xReset */ - 0 /* xRelease */ - }; - return &sDiskStore; -} -/* - * ---------------------------------------------------------- - * File: mem_kv.c - * MD5: 32e2610c95f53038114d9566f0d0489e - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: mem_kv.c v1.7 Win7 2012-11-28 01:41 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* - * This file implements an in-memory key value storage engine for unQLite. - * Note that this storage engine does not support transactions. - * - * Normaly, I (chm@symisc.net) planned to implement a red-black tree - * which is suitable for this kind of operation, but due to the lack - * of time, I decided to implement a tunned hashtable which everybody - * know works very well for this kind of operation. - * Again, I insist on a red-black tree implementation for future version - * of Unqlite. - */ -/* Forward declaration */ -typedef struct mem_hash_kv_engine mem_hash_kv_engine; -/* - * Each record is storead in an instance of the following structure. - */ -typedef struct mem_hash_record mem_hash_record; -struct mem_hash_record -{ - mem_hash_kv_engine *pEngine; /* Storage engine */ - sxu32 nHash; /* Hash of the key */ - const void *pKey; /* Key */ - sxu32 nKeyLen; /* Key size (Max 1GB) */ - const void *pData; /* Data */ - sxu32 nDataLen; /* Data length (Max 4GB) */ - mem_hash_record *pNext,*pPrev; /* Link to other records */ - mem_hash_record *pNextHash,*pPrevHash; /* Collision link */ -}; -/* - * Each in-memory KV engine is represented by an instance - * of the following structure. - */ -struct mem_hash_kv_engine -{ - const unqlite_kv_io *pIo; /* IO methods: MUST be first */ - /* Private data */ - SyMemBackend sAlloc; /* Private memory allocator */ - ProcHash xHash; /* Default hash function */ - ProcCmp xCmp; /* Default comparison function */ - sxu32 nRecord; /* Total number of records */ - sxu32 nBucket; /* Bucket size: Must be a power of two */ - mem_hash_record **apBucket; /* Hash bucket */ - mem_hash_record *pFirst; /* First inserted entry */ - mem_hash_record *pLast; /* Last inserted entry */ -}; -/* - * Allocate a new hash record. - */ -static mem_hash_record * MemHashNewRecord( - mem_hash_kv_engine *pEngine, - const void *pKey,int nKey, - const void *pData,unqlite_int64 nData, - sxu32 nHash - ) -{ - SyMemBackend *pAlloc = &pEngine->sAlloc; - mem_hash_record *pRecord; - void *pDupData; - sxu32 nByte; - char *zPtr; - - /* Total number of bytes to alloc */ - nByte = sizeof(mem_hash_record) + nKey; - /* Allocate a new instance */ - pRecord = (mem_hash_record *)SyMemBackendAlloc(pAlloc,nByte); - if( pRecord == 0 ){ - return 0; - } - pDupData = (void *)SyMemBackendAlloc(pAlloc,(sxu32)nData); - if( pDupData == 0 ){ - SyMemBackendFree(pAlloc,pRecord); - return 0; - } - zPtr = (char *)pRecord; - zPtr += sizeof(mem_hash_record); - /* Zero the structure */ - SyZero(pRecord,sizeof(mem_hash_record)); - /* Fill in the structure */ - pRecord->pEngine = pEngine; - pRecord->nDataLen = (sxu32)nData; - pRecord->nKeyLen = (sxu32)nKey; - pRecord->nHash = nHash; - SyMemcpy(pKey,zPtr,pRecord->nKeyLen); - pRecord->pKey = (const void *)zPtr; - SyMemcpy(pData,pDupData,pRecord->nDataLen); - pRecord->pData = pDupData; - /* All done */ - return pRecord; -} -/* - * Install a given record in the hashtable. - */ -static void MemHashLinkRecord(mem_hash_kv_engine *pEngine,mem_hash_record *pRecord) -{ - sxu32 nBucket = pRecord->nHash & (pEngine->nBucket - 1); - pRecord->pNextHash = pEngine->apBucket[nBucket]; - if( pEngine->apBucket[nBucket] ){ - pEngine->apBucket[nBucket]->pPrevHash = pRecord; - } - pEngine->apBucket[nBucket] = pRecord; - if( pEngine->pFirst == 0 ){ - pEngine->pFirst = pEngine->pLast = pRecord; - }else{ - MACRO_LD_PUSH(pEngine->pLast,pRecord); - } - pEngine->nRecord++; -} -/* - * Unlink a given record from the hashtable. - */ -static void MemHashUnlinkRecord(mem_hash_kv_engine *pEngine,mem_hash_record *pEntry) -{ - sxu32 nBucket = pEntry->nHash & (pEngine->nBucket - 1); - SyMemBackend *pAlloc = &pEngine->sAlloc; - if( pEntry->pPrevHash == 0 ){ - pEngine->apBucket[nBucket] = pEntry->pNextHash; - }else{ - pEntry->pPrevHash->pNextHash = pEntry->pNextHash; - } - if( pEntry->pNextHash ){ - pEntry->pNextHash->pPrevHash = pEntry->pPrevHash; - } - MACRO_LD_REMOVE(pEngine->pLast,pEntry); - if( pEntry == pEngine->pFirst ){ - pEngine->pFirst = pEntry->pPrev; - } - pEngine->nRecord--; - /* Release the entry */ - SyMemBackendFree(pAlloc,(void *)pEntry->pData); - SyMemBackendFree(pAlloc,pEntry); /* Key is also stored here */ -} -/* - * Perform a lookup for a given entry. - */ -static mem_hash_record * MemHashGetEntry( - mem_hash_kv_engine *pEngine, - const void *pKey,int nKeyLen - ) -{ - mem_hash_record *pEntry; - sxu32 nHash,nBucket; - /* Hash the entry */ - nHash = pEngine->xHash(pKey,(sxu32)nKeyLen); - nBucket = nHash & (pEngine->nBucket - 1); - pEntry = pEngine->apBucket[nBucket]; - for(;;){ - if( pEntry == 0 ){ - break; - } - if( pEntry->nHash == nHash && pEntry->nKeyLen == (sxu32)nKeyLen && - pEngine->xCmp(pEntry->pKey,pKey,pEntry->nKeyLen) == 0 ){ - return pEntry; - } - pEntry = pEntry->pNextHash; - } - /* No such entry */ - return 0; -} -/* - * Rehash all the entries in the given table. - */ -static int MemHashGrowTable(mem_hash_kv_engine *pEngine) -{ - sxu32 nNewSize = pEngine->nBucket << 1; - mem_hash_record *pEntry; - mem_hash_record **apNew; - sxu32 n,iBucket; - /* Allocate a new larger table */ - apNew = (mem_hash_record **)SyMemBackendAlloc(&pEngine->sAlloc, nNewSize * sizeof(mem_hash_record *)); - if( apNew == 0 ){ - /* Not so fatal, simply a performance hit */ - return UNQLITE_OK; - } - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(mem_hash_record *)); - /* Rehash all entries */ - n = 0; - pEntry = pEngine->pLast; - for(;;){ - - /* Loop one */ - if( n >= pEngine->nRecord ){ - break; - } - pEntry->pNextHash = pEntry->pPrevHash = 0; - /* Install in the new bucket */ - iBucket = pEntry->nHash & (nNewSize - 1); - pEntry->pNextHash = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevHash = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - - /* Loop two */ - if( n >= pEngine->nRecord ){ - break; - } - pEntry->pNextHash = pEntry->pPrevHash = 0; - /* Install in the new bucket */ - iBucket = pEntry->nHash & (nNewSize - 1); - pEntry->pNextHash = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevHash = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - - /* Loop three */ - if( n >= pEngine->nRecord ){ - break; - } - pEntry->pNextHash = pEntry->pPrevHash = 0; - /* Install in the new bucket */ - iBucket = pEntry->nHash & (nNewSize - 1); - pEntry->pNextHash = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevHash = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - - /* Loop four */ - if( n >= pEngine->nRecord ){ - break; - } - pEntry->pNextHash = pEntry->pPrevHash = 0; - /* Install in the new bucket */ - iBucket = pEntry->nHash & (nNewSize - 1); - pEntry->pNextHash = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevHash = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(&pEngine->sAlloc,(void *)pEngine->apBucket); - pEngine->apBucket = apNew; - pEngine->nBucket = nNewSize; - return UNQLITE_OK; -} -/* - * Exported Interfaces. - */ -/* - * Each public cursor is identified by an instance of this structure. - */ -typedef struct mem_hash_cursor mem_hash_cursor; -struct mem_hash_cursor -{ - unqlite_kv_engine *pStore; /* Must be first */ - /* Private fields */ - mem_hash_record *pCur; /* Current hash record */ -}; -/* - * Initialize the cursor. - */ -static void MemHashInitCursor(unqlite_kv_cursor *pCursor) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore; - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - /* Point to the first inserted entry */ - pMem->pCur = pEngine->pFirst; -} -/* - * Point to the first entry. - */ -static int MemHashCursorFirst(unqlite_kv_cursor *pCursor) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore; - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - pMem->pCur = pEngine->pFirst; - return UNQLITE_OK; -} -/* - * Point to the last entry. - */ -static int MemHashCursorLast(unqlite_kv_cursor *pCursor) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore; - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - pMem->pCur = pEngine->pLast; - return UNQLITE_OK; -} -/* - * is a Valid Cursor. - */ -static int MemHashCursorValid(unqlite_kv_cursor *pCursor) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - return pMem->pCur != 0 ? 1 : 0; -} -/* - * Point to the next entry. - */ -static int MemHashCursorNext(unqlite_kv_cursor *pCursor) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - if( pMem->pCur == 0){ - return UNQLITE_EOF; - } - pMem->pCur = pMem->pCur->pPrev; /* Reverse link: Not a Bug */ - return UNQLITE_OK; -} -/* - * Point to the previous entry. - */ -static int MemHashCursorPrev(unqlite_kv_cursor *pCursor) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - if( pMem->pCur == 0){ - return UNQLITE_EOF; - } - pMem->pCur = pMem->pCur->pNext; /* Reverse link: Not a Bug */ - return UNQLITE_OK; -} -/* - * Return key length. - */ -static int MemHashCursorKeyLength(unqlite_kv_cursor *pCursor,int *pLen) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - if( pMem->pCur == 0){ - return UNQLITE_EOF; - } - *pLen = (int)pMem->pCur->nKeyLen; - return UNQLITE_OK; -} -/* - * Return data length. - */ -static int MemHashCursorDataLength(unqlite_kv_cursor *pCursor,unqlite_int64 *pLen) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - if( pMem->pCur == 0 ){ - return UNQLITE_EOF; - } - *pLen = pMem->pCur->nDataLen; - return UNQLITE_OK; -} -/* - * Consume the key. - */ -static int MemHashCursorKey(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - int rc; - if( pMem->pCur == 0){ - return UNQLITE_EOF; - } - /* Invoke the callback */ - rc = xConsumer(pMem->pCur->pKey,pMem->pCur->nKeyLen,pUserData); - /* Callback result */ - return rc; -} -/* - * Consume the data. - */ -static int MemHashCursorData(unqlite_kv_cursor *pCursor,int (*xConsumer)(const void *,unsigned int,void *),void *pUserData) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - int rc; - if( pMem->pCur == 0){ - return UNQLITE_EOF; - } - /* Invoke the callback */ - rc = xConsumer(pMem->pCur->pData,pMem->pCur->nDataLen,pUserData); - /* Callback result */ - return rc; -} -/* - * Reset the cursor. - */ -static void MemHashCursorReset(unqlite_kv_cursor *pCursor) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - pMem->pCur = ((mem_hash_kv_engine *)pCursor->pStore)->pFirst; -} -/* - * Remove a particular record. - */ -static int MemHashCursorDelete(unqlite_kv_cursor *pCursor) -{ - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - mem_hash_record *pNext; - if( pMem->pCur == 0 ){ - /* Cursor does not point to anything */ - return UNQLITE_NOTFOUND; - } - pNext = pMem->pCur->pPrev; - /* Perform the deletion */ - MemHashUnlinkRecord(pMem->pCur->pEngine,pMem->pCur); - /* Point to the next entry */ - pMem->pCur = pNext; - return UNQLITE_OK; -} -/* - * Find a particular record. - */ -static int MemHashCursorSeek(unqlite_kv_cursor *pCursor,const void *pKey,int nByte,int iPos) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pCursor->pStore; - mem_hash_cursor *pMem = (mem_hash_cursor *)pCursor; - /* Perform the lookup */ - pMem->pCur = MemHashGetEntry(pEngine,pKey,nByte); - if( pMem->pCur == 0 ){ - if( iPos != UNQLITE_CURSOR_MATCH_EXACT ){ - /* noop; */ - } - /* No such record */ - return UNQLITE_NOTFOUND; - } - return UNQLITE_OK; -} -/* - * Builtin hash function. - */ -static sxu32 MemHashFunc(const void *pSrc,sxu32 nLen) -{ - register unsigned char *zIn = (unsigned char *)pSrc; - unsigned char *zEnd; - sxu32 nH = 5381; - zEnd = &zIn[nLen]; - for(;;){ - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - if( zIn >= zEnd ){ break; } nH = nH * 33 + zIn[0] ; zIn++; - } - return nH; -} -/* Default bucket size */ -#define MEM_HASH_BUCKET_SIZE 64 -/* Default fill factor */ -#define MEM_HASH_FILL_FACTOR 4 /* or 3 */ -/* - * Initialize the in-memory storage engine. - */ -static int MemHashInit(unqlite_kv_engine *pKvEngine,int iPageSize) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKvEngine; - /* Note that this instance is already zeroed */ - /* Memory backend */ - SyMemBackendInitFromParent(&pEngine->sAlloc,unqliteExportMemBackend()); -//#if defined(UNQLITE_ENABLE_THREADS) -// /* Already protected by the upper layers */ -// SyMemBackendDisbaleMutexing(&pEngine->sAlloc); -//#endif - /* Default hash & comparison function */ - pEngine->xHash = MemHashFunc; - pEngine->xCmp = SyMemcmp; - /* Allocate a new bucket */ - pEngine->apBucket = (mem_hash_record **)SyMemBackendAlloc(&pEngine->sAlloc,MEM_HASH_BUCKET_SIZE * sizeof(mem_hash_record *)); - if( pEngine->apBucket == 0 ){ - SXUNUSED(iPageSize); /* cc warning */ - return UNQLITE_NOMEM; - } - /* Zero the bucket */ - SyZero(pEngine->apBucket,MEM_HASH_BUCKET_SIZE * sizeof(mem_hash_record *)); - pEngine->nRecord = 0; - pEngine->nBucket = MEM_HASH_BUCKET_SIZE; - return UNQLITE_OK; -} -/* - * Release the in-memory storage engine. - */ -static void MemHashRelease(unqlite_kv_engine *pKvEngine) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKvEngine; - /* Release the private memory backend */ - SyMemBackendRelease(&pEngine->sAlloc); -} -/* - * Configure the in-memory storage engine. - */ -static int MemHashConfigure(unqlite_kv_engine *pKvEngine,int iOp,va_list ap) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKvEngine; - int rc = UNQLITE_OK; - switch(iOp){ - case UNQLITE_KV_CONFIG_HASH_FUNC:{ - /* Use a default hash function */ - if( pEngine->nRecord > 0 ){ - rc = UNQLITE_LOCKED; - }else{ - ProcHash xHash = va_arg(ap,ProcHash); - if( xHash ){ - pEngine->xHash = xHash; - } - } - break; - } - case UNQLITE_KV_CONFIG_CMP_FUNC: { - /* Default comparison function */ - ProcCmp xCmp = va_arg(ap,ProcCmp); - if( xCmp ){ - pEngine->xCmp = xCmp; - } - break; - } - default: - /* Unknown configuration option */ - rc = UNQLITE_UNKNOWN; - } - return rc; -} -/* - * Replace method. - */ -static int MemHashReplace( - unqlite_kv_engine *pKv, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKv; - mem_hash_record *pRecord; - if( nDataLen > SXU32_HIGH ){ - /* Database limit */ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"Record size limit reached"); - return UNQLITE_LIMIT; - } - /* Fetch the record first */ - pRecord = MemHashGetEntry(pEngine,pKey,nKeyLen); - if( pRecord == 0 ){ - /* Allocate a new record */ - pRecord = MemHashNewRecord(pEngine, - pKey,nKeyLen, - pData,nDataLen, - pEngine->xHash(pKey,nKeyLen) - ); - if( pRecord == 0 ){ - return UNQLITE_NOMEM; - } - /* Link the entry */ - MemHashLinkRecord(pEngine,pRecord); - if( (pEngine->nRecord >= pEngine->nBucket * MEM_HASH_FILL_FACTOR) && pEngine->nRecord < 100000 ){ - /* Rehash the table */ - MemHashGrowTable(pEngine); - } - }else{ - sxu32 nData = (sxu32)nDataLen; - void *pNew; - /* Replace an existing record */ - if( nData == pRecord->nDataLen ){ - /* No need to free the old chunk */ - pNew = (void *)pRecord->pData; - }else{ - pNew = SyMemBackendAlloc(&pEngine->sAlloc,nData); - if( pNew == 0 ){ - return UNQLITE_NOMEM; - } - /* Release the old data */ - SyMemBackendFree(&pEngine->sAlloc,(void *)pRecord->pData); - } - /* Reflect the change */ - pRecord->nDataLen = nData; - SyMemcpy(pData,pNew,nData); - pRecord->pData = pNew; - } - return UNQLITE_OK; -} -/* - * Append method. - */ -static int MemHashAppend( - unqlite_kv_engine *pKv, - const void *pKey,int nKeyLen, - const void *pData,unqlite_int64 nDataLen - ) -{ - mem_hash_kv_engine *pEngine = (mem_hash_kv_engine *)pKv; - mem_hash_record *pRecord; - if( nDataLen > SXU32_HIGH ){ - /* Database limit */ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"Record size limit reached"); - return UNQLITE_LIMIT; - } - /* Fetch the record first */ - pRecord = MemHashGetEntry(pEngine,pKey,nKeyLen); - if( pRecord == 0 ){ - /* Allocate a new record */ - pRecord = MemHashNewRecord(pEngine, - pKey,nKeyLen, - pData,nDataLen, - pEngine->xHash(pKey,nKeyLen) - ); - if( pRecord == 0 ){ - return UNQLITE_NOMEM; - } - /* Link the entry */ - MemHashLinkRecord(pEngine,pRecord); - if( pEngine->nRecord * MEM_HASH_FILL_FACTOR >= pEngine->nBucket && pEngine->nRecord < 100000 ){ - /* Rehash the table */ - MemHashGrowTable(pEngine); - } - }else{ - unqlite_int64 nNew = pRecord->nDataLen + nDataLen; - void *pOld = (void *)pRecord->pData; - sxu32 nData; - char *zNew; - /* Append data to the existing record */ - if( nNew > SXU32_HIGH ){ - /* Overflow */ - pEngine->pIo->xErr(pEngine->pIo->pHandle,"Append operation will cause data overflow"); - return UNQLITE_LIMIT; - } - nData = (sxu32)nNew; - /* Allocate bigger chunk */ - zNew = (char *)SyMemBackendRealloc(&pEngine->sAlloc,pOld,nData); - if( zNew == 0 ){ - return UNQLITE_NOMEM; - } - /* Reflect the change */ - SyMemcpy(pData,&zNew[pRecord->nDataLen],(sxu32)nDataLen); - pRecord->pData = (const void *)zNew; - pRecord->nDataLen = nData; - } - return UNQLITE_OK; -} -/* - * Export the in-memory storage engine. - */ -UNQLITE_PRIVATE const unqlite_kv_methods * unqliteExportMemKvStorage(void) -{ - static const unqlite_kv_methods sMemStore = { - "mem", /* zName */ - sizeof(mem_hash_kv_engine), /* szKv */ - sizeof(mem_hash_cursor), /* szCursor */ - 1, /* iVersion */ - MemHashInit, /* xInit */ - MemHashRelease, /* xRelease */ - MemHashConfigure, /* xConfig */ - 0, /* xOpen */ - MemHashReplace, /* xReplace */ - MemHashAppend, /* xAppend */ - MemHashInitCursor, /* xCursorInit */ - MemHashCursorSeek, /* xSeek */ - MemHashCursorFirst, /* xFirst */ - MemHashCursorLast, /* xLast */ - MemHashCursorValid, /* xValid */ - MemHashCursorNext, /* xNext */ - MemHashCursorPrev, /* xPrev */ - MemHashCursorDelete, /* xDelete */ - MemHashCursorKeyLength, /* xKeyLength */ - MemHashCursorKey, /* xKey */ - MemHashCursorDataLength, /* xDataLength */ - MemHashCursorData, /* xData */ - MemHashCursorReset, /* xReset */ - 0 /* xRelease */ - }; - return &sMemStore; -} -/* - * ---------------------------------------------------------- - * File: os.c - * MD5: e7ad243c3cd9e6aac5fba406eedb7766 - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: os.c v1.0 FreeBSD 2012-11-12 21:27 devel $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* OS interfaces abstraction layers: Mostly SQLite3 source tree */ -/* -** The following routines are convenience wrappers around methods -** of the unqlite_file object. This is mostly just syntactic sugar. All -** of this would be completely automatic if UnQLite were coded using -** C++ instead of plain old C. -*/ -UNQLITE_PRIVATE int unqliteOsRead(unqlite_file *id, void *pBuf, unqlite_int64 amt, unqlite_int64 offset) -{ - return id->pMethods->xRead(id, pBuf, amt, offset); -} -UNQLITE_PRIVATE int unqliteOsWrite(unqlite_file *id, const void *pBuf, unqlite_int64 amt, unqlite_int64 offset) -{ - return id->pMethods->xWrite(id, pBuf, amt, offset); -} -UNQLITE_PRIVATE int unqliteOsTruncate(unqlite_file *id, unqlite_int64 size) -{ - return id->pMethods->xTruncate(id, size); -} -UNQLITE_PRIVATE int unqliteOsSync(unqlite_file *id, int flags) -{ - return id->pMethods->xSync(id, flags); -} -UNQLITE_PRIVATE int unqliteOsFileSize(unqlite_file *id, unqlite_int64 *pSize) -{ - return id->pMethods->xFileSize(id, pSize); -} -UNQLITE_PRIVATE int unqliteOsLock(unqlite_file *id, int lockType) -{ - return id->pMethods->xLock(id, lockType); -} -UNQLITE_PRIVATE int unqliteOsUnlock(unqlite_file *id, int lockType) -{ - return id->pMethods->xUnlock(id, lockType); -} -UNQLITE_PRIVATE int unqliteOsCheckReservedLock(unqlite_file *id, int *pResOut) -{ - return id->pMethods->xCheckReservedLock(id, pResOut); -} -UNQLITE_PRIVATE int unqliteOsSectorSize(unqlite_file *id) -{ - if( id->pMethods->xSectorSize ){ - return id->pMethods->xSectorSize(id); - } - return UNQLITE_DEFAULT_SECTOR_SIZE; -} -/* -** The next group of routines are convenience wrappers around the -** VFS methods. -*/ -UNQLITE_PRIVATE int unqliteOsOpen( - unqlite_vfs *pVfs, - SyMemBackend *pAlloc, - const char *zPath, - unqlite_file **ppOut, - unsigned int flags -) -{ - unqlite_file *pFile; - int rc; - *ppOut = 0; - if( zPath == 0 ){ - /* May happen if dealing with an in-memory database */ - return SXERR_EMPTY; - } - /* Allocate a new instance */ - pFile = (unqlite_file *)SyMemBackendAlloc(pAlloc,sizeof(unqlite_file)+pVfs->szOsFile); - if( pFile == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pFile,sizeof(unqlite_file)+pVfs->szOsFile); - /* Invoke the xOpen method of the underlying VFS */ - rc = pVfs->xOpen(pVfs, zPath, pFile, flags); - if( rc != UNQLITE_OK ){ - SyMemBackendFree(pAlloc,pFile); - pFile = 0; - } - *ppOut = pFile; - return rc; -} -UNQLITE_PRIVATE int unqliteOsCloseFree(SyMemBackend *pAlloc,unqlite_file *pId) -{ - int rc = UNQLITE_OK; - if( pId ){ - rc = pId->pMethods->xClose(pId); - SyMemBackendFree(pAlloc,pId); - } - return rc; -} -UNQLITE_PRIVATE int unqliteOsDelete(unqlite_vfs *pVfs, const char *zPath, int dirSync){ - return pVfs->xDelete(pVfs, zPath, dirSync); -} -UNQLITE_PRIVATE int unqliteOsAccess( - unqlite_vfs *pVfs, - const char *zPath, - int flags, - int *pResOut -){ - return pVfs->xAccess(pVfs, zPath, flags, pResOut); -} -/* - * ---------------------------------------------------------- - * File: os_unix.c - * MD5: 5efd57d03f8fb988d081c5bcf5cc2998 - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: os_unix.c v1.3 FreeBSD 2013-04-05 01:10 devel $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* - * Omit the whole layer from the build if compiling for platforms other than Unix (Linux, BSD, Solaris, OS X, etc.). - * Note: Mostly SQLite3 source tree. - */ -#if defined(__UNIXES__) -/** This file contains the VFS implementation for unix-like operating systems -** include Linux, MacOSX, *BSD, QNX, VxWorks, AIX, HPUX, and others. -** -** There are actually several different VFS implementations in this file. -** The differences are in the way that file locking is done. The default -** implementation uses Posix Advisory Locks. Alternative implementations -** use flock(), dot-files, various proprietary locking schemas, or simply -** skip locking all together. -** -** This source file is organized into divisions where the logic for various -** subfunctions is contained within the appropriate division. PLEASE -** KEEP THE STRUCTURE OF THIS FILE INTACT. New code should be placed -** in the correct division and should be clearly labeled. -** -*/ -/* -** standard include files. -*/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if defined(__APPLE__) -# include -#endif -/* -** Allowed values of unixFile.fsFlags -*/ -#define UNQLITE_FSFLAGS_IS_MSDOS 0x1 - -/* -** Default permissions when creating a new file -*/ -#ifndef UNQLITE_DEFAULT_FILE_PERMISSIONS -# define UNQLITE_DEFAULT_FILE_PERMISSIONS 0644 -#endif -/* - ** Default permissions when creating auto proxy dir - */ -#ifndef UNQLITE_DEFAULT_PROXYDIR_PERMISSIONS -# define UNQLITE_DEFAULT_PROXYDIR_PERMISSIONS 0755 -#endif -/* -** Maximum supported path-length. -*/ -#define MAX_PATHNAME 512 -/* -** Only set the lastErrno if the error code is a real error and not -** a normal expected return code of UNQLITE_BUSY or UNQLITE_OK -*/ -#define IS_LOCK_ERROR(x) ((x != UNQLITE_OK) && (x != UNQLITE_BUSY)) -/* Forward references */ -typedef struct unixInodeInfo unixInodeInfo; /* An i-node */ -typedef struct UnixUnusedFd UnixUnusedFd; /* An unused file descriptor */ -/* -** Sometimes, after a file handle is closed by SQLite, the file descriptor -** cannot be closed immediately. In these cases, instances of the following -** structure are used to store the file descriptor while waiting for an -** opportunity to either close or reuse it. -*/ -struct UnixUnusedFd { - int fd; /* File descriptor to close */ - int flags; /* Flags this file descriptor was opened with */ - UnixUnusedFd *pNext; /* Next unused file descriptor on same file */ -}; -/* -** The unixFile structure is subclass of unqlite3_file specific to the unix -** VFS implementations. -*/ -typedef struct unixFile unixFile; -struct unixFile { - const unqlite_io_methods *pMethod; /* Always the first entry */ - unixInodeInfo *pInode; /* Info about locks on this inode */ - int h; /* The file descriptor */ - int dirfd; /* File descriptor for the directory */ - unsigned char eFileLock; /* The type of lock held on this fd */ - int lastErrno; /* The unix errno from last I/O error */ - void *lockingContext; /* Locking style specific state */ - UnixUnusedFd *pUnused; /* Pre-allocated UnixUnusedFd */ - int fileFlags; /* Miscellanous flags */ - const char *zPath; /* Name of the file */ - unsigned fsFlags; /* cached details from statfs() */ -}; -/* -** The following macros define bits in unixFile.fileFlags -*/ -#define UNQLITE_WHOLE_FILE_LOCKING 0x0001 /* Use whole-file locking */ -/* -** Define various macros that are missing from some systems. -*/ -#ifndef O_LARGEFILE -# define O_LARGEFILE 0 -#endif -#ifndef O_NOFOLLOW -# define O_NOFOLLOW 0 -#endif -#ifndef O_BINARY -# define O_BINARY 0 -#endif -/* -** Helper functions to obtain and relinquish the global mutex. The -** global mutex is used to protect the unixInodeInfo and -** vxworksFileId objects used by this file, all of which may be -** shared by multiple threads. -** -** Function unixMutexHeld() is used to assert() that the global mutex -** is held when required. This function is only used as part of assert() -** statements. e.g. -** -** unixEnterMutex() -** assert( unixMutexHeld() ); -** unixEnterLeave() -*/ -static void unixEnterMutex(void){ -#ifdef UNQLITE_ENABLE_THREADS - const SyMutexMethods *pMutexMethods = SyMutexExportMethods(); - if( pMutexMethods ){ - SyMutex *pMutex = pMutexMethods->xNew(SXMUTEX_TYPE_STATIC_2); /* pre-allocated, never fail */ - SyMutexEnter(pMutexMethods,pMutex); - } -#endif /* UNQLITE_ENABLE_THREADS */ -} -static void unixLeaveMutex(void){ -#ifdef UNQLITE_ENABLE_THREADS - const SyMutexMethods *pMutexMethods = SyMutexExportMethods(); - if( pMutexMethods ){ - SyMutex *pMutex = pMutexMethods->xNew(SXMUTEX_TYPE_STATIC_2); /* pre-allocated, never fail */ - SyMutexLeave(pMutexMethods,pMutex); - } -#endif /* UNQLITE_ENABLE_THREADS */ -} -/* -** This routine translates a standard POSIX errno code into something -** useful to the clients of the unqlite3 functions. Specifically, it is -** intended to translate a variety of "try again" errors into UNQLITE_BUSY -** and a variety of "please close the file descriptor NOW" errors into -** UNQLITE_IOERR -** -** Errors during initialization of locks, or file system support for locks, -** should handle ENOLCK, ENOTSUP, EOPNOTSUPP separately. -*/ -static int unqliteErrorFromPosixError(int posixError, int unqliteIOErr) { - switch (posixError) { - case 0: - return UNQLITE_OK; - - case EAGAIN: - case ETIMEDOUT: - case EBUSY: - case EINTR: - case ENOLCK: - /* random NFS retry error, unless during file system support - * introspection, in which it actually means what it says */ - return UNQLITE_BUSY; - - case EACCES: - /* EACCES is like EAGAIN during locking operations, but not any other time*/ - return UNQLITE_BUSY; - - case EPERM: - return UNQLITE_PERM; - - case EDEADLK: - return UNQLITE_IOERR; - -#if EOPNOTSUPP!=ENOTSUP - case EOPNOTSUPP: - /* something went terribly awry, unless during file system support - * introspection, in which it actually means what it says */ -#endif -#ifdef ENOTSUP - case ENOTSUP: - /* invalid fd, unless during file system support introspection, in which - * it actually means what it says */ -#endif - case EIO: - case EBADF: - case EINVAL: - case ENOTCONN: - case ENODEV: - case ENXIO: - case ENOENT: - case ESTALE: - case ENOSYS: - /* these should force the client to close the file and reconnect */ - - default: - return unqliteIOErr; - } -} -/****************************************************************************** -*************************** Posix Advisory Locking **************************** -** -** POSIX advisory locks are broken by design. ANSI STD 1003.1 (1996) -** section 6.5.2.2 lines 483 through 490 specify that when a process -** sets or clears a lock, that operation overrides any prior locks set -** by the same process. It does not explicitly say so, but this implies -** that it overrides locks set by the same process using a different -** file descriptor. Consider this test case: -** -** int fd1 = open("./file1", O_RDWR|O_CREAT, 0644); -** int fd2 = open("./file2", O_RDWR|O_CREAT, 0644); -** -** Suppose ./file1 and ./file2 are really the same file (because -** one is a hard or symbolic link to the other) then if you set -** an exclusive lock on fd1, then try to get an exclusive lock -** on fd2, it works. I would have expected the second lock to -** fail since there was already a lock on the file due to fd1. -** But not so. Since both locks came from the same process, the -** second overrides the first, even though they were on different -** file descriptors opened on different file names. -** -** This means that we cannot use POSIX locks to synchronize file access -** among competing threads of the same process. POSIX locks will work fine -** to synchronize access for threads in separate processes, but not -** threads within the same process. -** -** To work around the problem, SQLite has to manage file locks internally -** on its own. Whenever a new database is opened, we have to find the -** specific inode of the database file (the inode is determined by the -** st_dev and st_ino fields of the stat structure that fstat() fills in) -** and check for locks already existing on that inode. When locks are -** created or removed, we have to look at our own internal record of the -** locks to see if another thread has previously set a lock on that same -** inode. -** -** (Aside: The use of inode numbers as unique IDs does not work on VxWorks. -** For VxWorks, we have to use the alternative unique ID system based on -** canonical filename and implemented in the previous division.) -** -** There is one locking structure -** per inode, so if the same inode is opened twice, both unixFile structures -** point to the same locking structure. The locking structure keeps -** a reference count (so we will know when to delete it) and a "cnt" -** field that tells us its internal lock status. cnt==0 means the -** file is unlocked. cnt==-1 means the file has an exclusive lock. -** cnt>0 means there are cnt shared locks on the file. -** -** Any attempt to lock or unlock a file first checks the locking -** structure. The fcntl() system call is only invoked to set a -** POSIX lock if the internal lock structure transitions between -** a locked and an unlocked state. -** -** But wait: there are yet more problems with POSIX advisory locks. -** -** If you close a file descriptor that points to a file that has locks, -** all locks on that file that are owned by the current process are -** released. To work around this problem, each unixInodeInfo object -** maintains a count of the number of pending locks on that inode. -** When an attempt is made to close an unixFile, if there are -** other unixFile open on the same inode that are holding locks, the call -** to close() the file descriptor is deferred until all of the locks clear. -** The unixInodeInfo structure keeps a list of file descriptors that need to -** be closed and that list is walked (and cleared) when the last lock -** clears. -** -** Yet another problem: LinuxThreads do not play well with posix locks. -** -** Many older versions of linux use the LinuxThreads library which is -** not posix compliant. Under LinuxThreads, a lock created by thread -** A cannot be modified or overridden by a different thread B. -** Only thread A can modify the lock. Locking behavior is correct -** if the appliation uses the newer Native Posix Thread Library (NPTL) -** on linux - with NPTL a lock created by thread A can override locks -** in thread B. But there is no way to know at compile-time which -** threading library is being used. So there is no way to know at -** compile-time whether or not thread A can override locks on thread B. -** One has to do a run-time check to discover the behavior of the -** current process. -** -*/ - -/* -** An instance of the following structure serves as the key used -** to locate a particular unixInodeInfo object. -*/ -struct unixFileId { - dev_t dev; /* Device number */ - ino_t ino; /* Inode number */ -}; -/* -** An instance of the following structure is allocated for each open -** inode. Or, on LinuxThreads, there is one of these structures for -** each inode opened by each thread. -** -** A single inode can have multiple file descriptors, so each unixFile -** structure contains a pointer to an instance of this object and this -** object keeps a count of the number of unixFile pointing to it. -*/ -struct unixInodeInfo { - struct unixFileId fileId; /* The lookup key */ - int nShared; /* Number of SHARED locks held */ - int eFileLock; /* One of SHARED_LOCK, RESERVED_LOCK etc. */ - int nRef; /* Number of pointers to this structure */ - int nLock; /* Number of outstanding file locks */ - UnixUnusedFd *pUnused; /* Unused file descriptors to close */ - unixInodeInfo *pNext; /* List of all unixInodeInfo objects */ - unixInodeInfo *pPrev; /* .... doubly linked */ -}; - -static unixInodeInfo *inodeList = 0; -/* - * Local memory allocation stuff. - */ -void * unqlite_malloc(unsigned int nByte) -{ - SyMemBackend *pAlloc; - void *p; - pAlloc = (SyMemBackend *)unqliteExportMemBackend(); - p = SyMemBackendAlloc(pAlloc,nByte); - return p; -} -void unqlite_free(void *p) -{ - SyMemBackend *pAlloc; - pAlloc = (SyMemBackend *)unqliteExportMemBackend(); - SyMemBackendFree(pAlloc,p); -} -/* -** Close all file descriptors accumuated in the unixInodeInfo->pUnused list. -** If all such file descriptors are closed without error, the list is -** cleared and UNQLITE_OK returned. -** -** Otherwise, if an error occurs, then successfully closed file descriptor -** entries are removed from the list, and UNQLITE_IOERR_CLOSE returned. -** not deleted and UNQLITE_IOERR_CLOSE returned. -*/ -static int closePendingFds(unixFile *pFile){ - int rc = UNQLITE_OK; - unixInodeInfo *pInode = pFile->pInode; - UnixUnusedFd *pError = 0; - UnixUnusedFd *p; - UnixUnusedFd *pNext; - for(p=pInode->pUnused; p; p=pNext){ - pNext = p->pNext; - if( close(p->fd) ){ - pFile->lastErrno = errno; - rc = UNQLITE_IOERR; - p->pNext = pError; - pError = p; - }else{ - unqlite_free(p); - } - } - pInode->pUnused = pError; - return rc; -} -/* -** Release a unixInodeInfo structure previously allocated by findInodeInfo(). -** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. -*/ -static void releaseInodeInfo(unixFile *pFile){ - unixInodeInfo *pInode = pFile->pInode; - if( pInode ){ - pInode->nRef--; - if( pInode->nRef==0 ){ - closePendingFds(pFile); - if( pInode->pPrev ){ - pInode->pPrev->pNext = pInode->pNext; - }else{ - inodeList = pInode->pNext; - } - if( pInode->pNext ){ - pInode->pNext->pPrev = pInode->pPrev; - } - unqlite_free(pInode); - } - } -} -/* -** Given a file descriptor, locate the unixInodeInfo object that -** describes that file descriptor. Create a new one if necessary. The -** return value might be uninitialized if an error occurs. -** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. -** -** Return an appropriate error code. -*/ -static int findInodeInfo( - unixFile *pFile, /* Unix file with file desc used in the key */ - unixInodeInfo **ppInode /* Return the unixInodeInfo object here */ -){ - int rc; /* System call return code */ - int fd; /* The file descriptor for pFile */ - struct unixFileId fileId; /* Lookup key for the unixInodeInfo */ - struct stat statbuf; /* Low-level file information */ - unixInodeInfo *pInode = 0; /* Candidate unixInodeInfo object */ - - /* Get low-level information about the file that we can used to - ** create a unique name for the file. - */ - fd = pFile->h; - rc = fstat(fd, &statbuf); - if( rc!=0 ){ - pFile->lastErrno = errno; -#ifdef EOVERFLOW - if( pFile->lastErrno==EOVERFLOW ) return UNQLITE_NOTIMPLEMENTED; -#endif - return UNQLITE_IOERR; - } - -#ifdef __APPLE__ - /* On OS X on an msdos filesystem, the inode number is reported - ** incorrectly for zero-size files. See ticket #3260. To work - ** around this problem (we consider it a bug in OS X, not SQLite) - ** we always increase the file size to 1 by writing a single byte - ** prior to accessing the inode number. The one byte written is - ** an ASCII 'S' character which also happens to be the first byte - ** in the header of every SQLite database. In this way, if there - ** is a race condition such that another thread has already populated - ** the first page of the database, no damage is done. - */ - if( statbuf.st_size==0 && (pFile->fsFlags & UNQLITE_FSFLAGS_IS_MSDOS)!=0 ){ - rc = write(fd, "S", 1); - if( rc!=1 ){ - pFile->lastErrno = errno; - return UNQLITE_IOERR; - } - rc = fstat(fd, &statbuf); - if( rc!=0 ){ - pFile->lastErrno = errno; - return UNQLITE_IOERR; - } - } -#endif - SyZero(&fileId,sizeof(fileId)); - fileId.dev = statbuf.st_dev; - fileId.ino = statbuf.st_ino; - pInode = inodeList; - while( pInode && SyMemcmp((const void *)&fileId,(const void *)&pInode->fileId, sizeof(fileId)) ){ - pInode = pInode->pNext; - } - if( pInode==0 ){ - pInode = (unixInodeInfo *)unqlite_malloc( sizeof(*pInode) ); - if( pInode==0 ){ - return UNQLITE_NOMEM; - } - SyZero(pInode,sizeof(*pInode)); - SyMemcpy((const void *)&fileId,(void *)&pInode->fileId,sizeof(fileId)); - pInode->nRef = 1; - pInode->pNext = inodeList; - pInode->pPrev = 0; - if( inodeList ) inodeList->pPrev = pInode; - inodeList = pInode; - }else{ - pInode->nRef++; - } - *ppInode = pInode; - return UNQLITE_OK; -} -/* -** 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 UNQLITE_OK unless an I/O error occurs during lock checking. -*/ -static int unixCheckReservedLock(unqlite_file *id, int *pResOut){ - int rc = UNQLITE_OK; - int reserved = 0; - unixFile *pFile = (unixFile*)id; - - - unixEnterMutex(); /* Because pFile->pInode is shared across threads */ - - /* Check if a thread in this process holds such a lock */ - if( pFile->pInode->eFileLock>SHARED_LOCK ){ - reserved = 1; - } - - /* Otherwise see if some other process holds it. - */ - if( !reserved ){ - struct flock lock; - lock.l_whence = SEEK_SET; - lock.l_start = RESERVED_BYTE; - lock.l_len = 1; - lock.l_type = F_WRLCK; - if (-1 == fcntl(pFile->h, F_GETLK, &lock)) { - int tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - pFile->lastErrno = tErrno; - } else if( lock.l_type!=F_UNLCK ){ - reserved = 1; - } - } - - unixLeaveMutex(); - - *pResOut = reserved; - return rc; -} -/* -** Lock the file with the lock specified by parameter eFileLock - one -** of the following: -** -** (1) SHARED_LOCK -** (2) RESERVED_LOCK -** (3) PENDING_LOCK -** (4) EXCLUSIVE_LOCK -** -** Sometimes when requesting one lock state, additional lock states -** are inserted in between. The locking might fail on one of the later -** transitions leaving the lock state different from what it started but -** still short of its goal. The following chart shows the allowed -** transitions and the inserted intermediate states: -** -** UNLOCKED -> SHARED -** SHARED -> RESERVED -** SHARED -> (PENDING) -> EXCLUSIVE -** RESERVED -> (PENDING) -> EXCLUSIVE -** PENDING -> EXCLUSIVE -** -** This routine will only increase a lock. Use the unqliteOsUnlock() -** routine to lower a locking level. -*/ -static int unixLock(unqlite_file *id, int eFileLock){ - /* The following describes the implementation of the various locks and - ** lock transitions in terms of the POSIX advisory shared and exclusive - ** lock primitives (called read-locks and write-locks below, to avoid - ** confusion with SQLite lock names). The algorithms are complicated - ** slightly in order to be compatible with unixdows systems simultaneously - ** accessing the same database file, in case that is ever required. - ** - ** Symbols defined in os.h indentify the 'pending byte' and the 'reserved - ** byte', each single bytes at well known offsets, and the 'shared byte - ** range', a range of 510 bytes at a well known offset. - ** - ** To obtain a SHARED lock, a read-lock is obtained on the 'pending - ** byte'. If this is successful, a random byte from the 'shared byte - ** range' is read-locked and the lock on the 'pending byte' released. - ** - ** A process may only obtain a RESERVED lock after it has a SHARED lock. - ** A RESERVED lock is implemented by grabbing a write-lock on the - ** 'reserved byte'. - ** - ** A process may only obtain a PENDING lock after it has obtained a - ** SHARED lock. A PENDING lock is implemented by obtaining a write-lock - ** on the 'pending byte'. This ensures that no new SHARED locks can be - ** obtained, but existing SHARED locks are allowed to persist. A process - ** does not have to obtain a RESERVED lock on the way to a PENDING lock. - ** This property is used by the algorithm for rolling back a journal file - ** after a crash. - ** - ** An EXCLUSIVE lock, obtained after a PENDING lock is held, is - ** implemented by obtaining a write-lock on the entire 'shared byte - ** range'. Since all other locks require a read-lock on one of the bytes - ** within this range, this ensures that no other locks are held on the - ** database. - ** - ** The reason a single byte cannot be used instead of the 'shared byte - ** range' is that some versions of unixdows do not support read-locks. By - ** locking a random byte from a range, concurrent SHARED locks may exist - ** even if the locking primitive used is always a write-lock. - */ - int rc = UNQLITE_OK; - unixFile *pFile = (unixFile*)id; - unixInodeInfo *pInode = pFile->pInode; - struct flock lock; - int s = 0; - int tErrno = 0; - - /* If there is already a lock of this type or more restrictive on the - ** unixFile, do nothing. Don't use the end_lock: exit path, as - ** unixEnterMutex() hasn't been called yet. - */ - if( pFile->eFileLock>=eFileLock ){ - return UNQLITE_OK; - } - /* This mutex is needed because pFile->pInode is shared across threads - */ - unixEnterMutex(); - pInode = pFile->pInode; - - /* If some thread using this PID has a lock via a different unixFile* - ** handle that precludes the requested lock, return BUSY. - */ - if( (pFile->eFileLock!=pInode->eFileLock && - (pInode->eFileLock>=PENDING_LOCK || eFileLock>SHARED_LOCK)) - ){ - rc = UNQLITE_BUSY; - goto end_lock; - } - - /* If a SHARED lock is requested, and some thread using this PID already - ** has a SHARED or RESERVED lock, then increment reference counts and - ** return UNQLITE_OK. - */ - if( eFileLock==SHARED_LOCK && - (pInode->eFileLock==SHARED_LOCK || pInode->eFileLock==RESERVED_LOCK) ){ - pFile->eFileLock = SHARED_LOCK; - pInode->nShared++; - pInode->nLock++; - goto end_lock; - } - /* A PENDING lock is needed before acquiring a SHARED lock and before - ** acquiring an EXCLUSIVE lock. For the SHARED lock, the PENDING will - ** be released. - */ - lock.l_len = 1L; - lock.l_whence = SEEK_SET; - if( eFileLock==SHARED_LOCK - || (eFileLock==EXCLUSIVE_LOCK && pFile->eFileLockh, F_SETLK, &lock); - if( s==(-1) ){ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_lock; - } - } - /* If control gets to this point, then actually go ahead and make - ** operating system calls for the specified lock. - */ - if( eFileLock==SHARED_LOCK ){ - /* Now get the read-lock */ - lock.l_start = SHARED_FIRST; - lock.l_len = SHARED_SIZE; - if( (s = fcntl(pFile->h, F_SETLK, &lock))==(-1) ){ - tErrno = errno; - } - /* Drop the temporary PENDING lock */ - lock.l_start = PENDING_BYTE; - lock.l_len = 1L; - lock.l_type = F_UNLCK; - if( fcntl(pFile->h, F_SETLK, &lock)!=0 ){ - if( s != -1 ){ - /* This could happen with a network mount */ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_lock; - } - } - if( s==(-1) ){ - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - }else{ - pFile->eFileLock = SHARED_LOCK; - pInode->nLock++; - pInode->nShared = 1; - } - }else if( eFileLock==EXCLUSIVE_LOCK && pInode->nShared>1 ){ - /* We are trying for an exclusive lock but another thread in this - ** same process is still holding a shared lock. */ - rc = UNQLITE_BUSY; - }else{ - /* The request was for a RESERVED or EXCLUSIVE lock. It is - ** assumed that there is a SHARED or greater lock on the file - ** already. - */ - lock.l_type = F_WRLCK; - switch( eFileLock ){ - case RESERVED_LOCK: - lock.l_start = RESERVED_BYTE; - break; - case EXCLUSIVE_LOCK: - lock.l_start = SHARED_FIRST; - lock.l_len = SHARED_SIZE; - break; - default: - /* Can't happen */ - break; - } - s = fcntl(pFile->h, F_SETLK, &lock); - if( s==(-1) ){ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - } - } - if( rc==UNQLITE_OK ){ - pFile->eFileLock = eFileLock; - pInode->eFileLock = eFileLock; - }else if( eFileLock==EXCLUSIVE_LOCK ){ - pFile->eFileLock = PENDING_LOCK; - pInode->eFileLock = PENDING_LOCK; - } -end_lock: - unixLeaveMutex(); - return rc; -} -/* -** Add the file descriptor used by file handle pFile to the corresponding -** pUnused list. -*/ -static void setPendingFd(unixFile *pFile){ - unixInodeInfo *pInode = pFile->pInode; - UnixUnusedFd *p = pFile->pUnused; - p->pNext = pInode->pUnused; - pInode->pUnused = p; - pFile->h = -1; - pFile->pUnused = 0; -} -/* -** Lower the locking level on file descriptor pFile to eFileLock. eFileLock -** must be either NO_LOCK or SHARED_LOCK. -** -** If the locking level of the file descriptor is already at or below -** the requested locking level, this routine is a no-op. -** -** If handleNFSUnlock is true, then on downgrading an EXCLUSIVE_LOCK to SHARED -** the byte range is divided into 2 parts and the first part is unlocked then -** set to a read lock, then the other part is simply unlocked. This works -** around a bug in BSD NFS lockd (also seen on MacOSX 10.3+) that fails to -** remove the write lock on a region when a read lock is set. -*/ -static int _posixUnlock(unqlite_file *id, int eFileLock, int handleNFSUnlock){ - unixFile *pFile = (unixFile*)id; - unixInodeInfo *pInode; - struct flock lock; - int rc = UNQLITE_OK; - int h; - int tErrno; /* Error code from system call errors */ - - if( pFile->eFileLock<=eFileLock ){ - return UNQLITE_OK; - } - unixEnterMutex(); - - h = pFile->h; - pInode = pFile->pInode; - - if( pFile->eFileLock>SHARED_LOCK ){ - /* downgrading to a shared lock on NFS involves clearing the write lock - ** before establishing the readlock - to avoid a race condition we downgrade - ** the lock in 2 blocks, so that part of the range will be covered by a - ** write lock until the rest is covered by a read lock: - ** 1: [WWWWW] - ** 2: [....W] - ** 3: [RRRRW] - ** 4: [RRRR.] - */ - if( eFileLock==SHARED_LOCK ){ - if( handleNFSUnlock ){ - off_t divSize = SHARED_SIZE - 1; - - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = SHARED_FIRST; - lock.l_len = divSize; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_unlock; - } - lock.l_type = F_RDLCK; - lock.l_whence = SEEK_SET; - lock.l_start = SHARED_FIRST; - lock.l_len = divSize; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_unlock; - } - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = SHARED_FIRST+divSize; - lock.l_len = SHARED_SIZE-divSize; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_unlock; - } - }else{ - lock.l_type = F_RDLCK; - lock.l_whence = SEEK_SET; - lock.l_start = SHARED_FIRST; - lock.l_len = SHARED_SIZE; - if( fcntl(h, F_SETLK, &lock)==(-1) ){ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_unlock; - } - } - } - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = PENDING_BYTE; - lock.l_len = 2L; - if( fcntl(h, F_SETLK, &lock)!=(-1) ){ - pInode->eFileLock = SHARED_LOCK; - }else{ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - goto end_unlock; - } - } - if( eFileLock==NO_LOCK ){ - /* Decrement the shared lock counter. Release the lock using an - ** OS call only when all threads in this same process have released - ** the lock. - */ - pInode->nShared--; - if( pInode->nShared==0 ){ - lock.l_type = F_UNLCK; - lock.l_whence = SEEK_SET; - lock.l_start = lock.l_len = 0L; - - if( fcntl(h, F_SETLK, &lock)!=(-1) ){ - pInode->eFileLock = NO_LOCK; - }else{ - tErrno = errno; - rc = unqliteErrorFromPosixError(tErrno, UNQLITE_LOCKERR); - if( IS_LOCK_ERROR(rc) ){ - pFile->lastErrno = tErrno; - } - pInode->eFileLock = NO_LOCK; - pFile->eFileLock = NO_LOCK; - } - } - - /* Decrement the count of locks against this same file. When the - ** count reaches zero, close any other file descriptors whose close - ** was deferred because of outstanding locks. - */ - pInode->nLock--; - - if( pInode->nLock==0 ){ - int rc2 = closePendingFds(pFile); - if( rc==UNQLITE_OK ){ - rc = rc2; - } - } - } - -end_unlock: - - unixLeaveMutex(); - - if( rc==UNQLITE_OK ) pFile->eFileLock = eFileLock; - return rc; -} -/* -** Lower the locking level on file descriptor pFile to eFileLock. eFileLock -** must be either NO_LOCK or SHARED_LOCK. -** -** If the locking level of the file descriptor is already at or below -** the requested locking level, this routine is a no-op. -*/ -static int unixUnlock(unqlite_file *id, int eFileLock){ - return _posixUnlock(id, eFileLock, 0); -} -/* -** This function performs the parts of the "close file" operation -** common to all locking schemes. It closes the directory and file -** handles, if they are valid, and sets all fields of the unixFile -** structure to 0. -** -*/ -static int closeUnixFile(unqlite_file *id){ - unixFile *pFile = (unixFile*)id; - if( pFile ){ - if( pFile->dirfd>=0 ){ - int err = close(pFile->dirfd); - if( err ){ - pFile->lastErrno = errno; - return UNQLITE_IOERR; - }else{ - pFile->dirfd=-1; - } - } - if( pFile->h>=0 ){ - int err = close(pFile->h); - if( err ){ - pFile->lastErrno = errno; - return UNQLITE_IOERR; - } - } - unqlite_free(pFile->pUnused); - SyZero(pFile,sizeof(unixFile)); - } - return UNQLITE_OK; -} -/* -** Close a file. -*/ -static int unixClose(unqlite_file *id){ - int rc = UNQLITE_OK; - if( id ){ - unixFile *pFile = (unixFile *)id; - unixUnlock(id, NO_LOCK); - unixEnterMutex(); - if( pFile->pInode && pFile->pInode->nLock ){ - /* If there are outstanding locks, do not actually close the file just - ** yet because that would clear those locks. Instead, add the file - ** descriptor to pInode->pUnused list. It will be automatically closed - ** when the last lock is cleared. - */ - setPendingFd(pFile); - } - releaseInodeInfo(pFile); - rc = closeUnixFile(id); - unixLeaveMutex(); - } - return rc; -} -/************** End of the posix advisory lock implementation ***************** -******************************************************************************/ -/* -** -** The next division contains implementations for all methods of the -** unqlite_file object other than the locking methods. The locking -** methods were defined in divisions above (one locking method per -** division). Those methods that are common to all locking modes -** are gather together into this division. -*/ -/* -** Seek to the offset passed as the second argument, then read cnt -** bytes into pBuf. Return the number of bytes actually read. -** -** NB: If you define USE_PREAD or USE_PREAD64, then it might also -** be necessary to define _XOPEN_SOURCE to be 500. This varies from -** one system to another. Since SQLite does not define USE_PREAD -** any form by default, we will not attempt to define _XOPEN_SOURCE. -** See tickets #2741 and #2681. -** -** To avoid stomping the errno value on a failed read the lastErrno value -** is set before returning. -*/ -static int seekAndRead(unixFile *id, unqlite_int64 offset, void *pBuf, int cnt){ - int got; -#if (!defined(USE_PREAD) && !defined(USE_PREAD64)) - unqlite_int64 newOffset; -#endif - -#if defined(USE_PREAD) - got = pread(id->h, pBuf, cnt, offset); -#elif defined(USE_PREAD64) - got = pread64(id->h, pBuf, cnt, offset); -#else - newOffset = lseek(id->h, offset, SEEK_SET); - - if( newOffset!=offset ){ - if( newOffset == -1 ){ - ((unixFile*)id)->lastErrno = errno; - }else{ - ((unixFile*)id)->lastErrno = 0; - } - return -1; - } - got = read(id->h, pBuf, cnt); -#endif - if( got<0 ){ - ((unixFile*)id)->lastErrno = errno; - } - return got; -} -/* -** Read data from a file into a buffer. Return UNQLITE_OK if all -** bytes were read successfully and UNQLITE_IOERR if anything goes -** wrong. -*/ -static int unixRead( - unqlite_file *id, - void *pBuf, - unqlite_int64 amt, - unqlite_int64 offset -){ - unixFile *pFile = (unixFile *)id; - int got; - - got = seekAndRead(pFile, offset, pBuf, (int)amt); - if( got==(int)amt ){ - return UNQLITE_OK; - }else if( got<0 ){ - /* lastErrno set by seekAndRead */ - return UNQLITE_IOERR; - }else{ - pFile->lastErrno = 0; /* not a system error */ - /* Unread parts of the buffer must be zero-filled */ - SyZero(&((char*)pBuf)[got],(sxu32)amt-got); - return UNQLITE_IOERR; - } -} -/* -** Seek to the offset in id->offset then read cnt bytes into pBuf. -** Return the number of bytes actually read. Update the offset. -** -** To avoid stomping the errno value on a failed write the lastErrno value -** is set before returning. -*/ -static int seekAndWrite(unixFile *id, unqlite_int64 offset, const void *pBuf, unqlite_int64 cnt){ - int got; -#if (!defined(USE_PREAD) && !defined(USE_PREAD64)) - unqlite_int64 newOffset; -#endif - -#if defined(USE_PREAD) - got = pwrite(id->h, pBuf, cnt, offset); -#elif defined(USE_PREAD64) - got = pwrite64(id->h, pBuf, cnt, offset); -#else - newOffset = lseek(id->h, offset, SEEK_SET); - if( newOffset!=offset ){ - if( newOffset == -1 ){ - ((unixFile*)id)->lastErrno = errno; - }else{ - ((unixFile*)id)->lastErrno = 0; - } - return -1; - } - got = write(id->h, pBuf, cnt); -#endif - if( got<0 ){ - ((unixFile*)id)->lastErrno = errno; - } - return got; -} -/* -** Write data from a buffer into a file. Return UNQLITE_OK on success -** or some other error code on failure. -*/ -static int unixWrite( - unqlite_file *id, - const void *pBuf, - unqlite_int64 amt, - unqlite_int64 offset -){ - unixFile *pFile = (unixFile*)id; - int wrote = 0; - - while( amt>0 && (wrote = seekAndWrite(pFile, offset, pBuf, amt))>0 ){ - amt -= wrote; - offset += wrote; - pBuf = &((char*)pBuf)[wrote]; - } - - if( amt>0 ){ - if( wrote<0 ){ - /* lastErrno set by seekAndWrite */ - return UNQLITE_IOERR; - }else{ - pFile->lastErrno = 0; /* not a system error */ - return UNQLITE_FULL; - } - } - return UNQLITE_OK; -} -/* -** We do not trust systems to provide a working fdatasync(). Some do. -** Others do no. To be safe, we will stick with the (slower) fsync(). -** If you know that your system does support fdatasync() correctly, -** then simply compile with -Dfdatasync=fdatasync -*/ -#if !defined(fdatasync) && !defined(__linux__) -# define fdatasync fsync -#endif - -/* -** Define HAVE_FULLFSYNC to 0 or 1 depending on whether or not -** the F_FULLFSYNC macro is defined. F_FULLFSYNC is currently -** only available on Mac OS X. But that could change. -*/ -#ifdef F_FULLFSYNC -# define HAVE_FULLFSYNC 1 -#else -# define HAVE_FULLFSYNC 0 -#endif -/* -** The fsync() system call does not work as advertised on many -** unix systems. The following procedure is an attempt to make -** it work better. -** -** -** SQLite sets the dataOnly flag if the size of the file is unchanged. -** The idea behind dataOnly is that it should only write the file content -** to disk, not the inode. We only set dataOnly if the file size is -** unchanged since the file size is part of the inode. However, -** Ted Ts'o tells us that fdatasync() will also write the inode if the -** file size has changed. The only real difference between fdatasync() -** and fsync(), Ted tells us, is that fdatasync() will not flush the -** inode if the mtime or owner or other inode attributes have changed. -** We only care about the file size, not the other file attributes, so -** as far as SQLite is concerned, an fdatasync() is always adequate. -** So, we always use fdatasync() if it is available, regardless of -** the value of the dataOnly flag. -*/ -static int full_fsync(int fd, int fullSync, int dataOnly){ - int rc; -#if HAVE_FULLFSYNC - SXUNUSED(dataOnly); -#else - SXUNUSED(fullSync); - SXUNUSED(dataOnly); -#endif - - /* If we compiled with the UNQLITE_NO_SYNC flag, then syncing is a - ** no-op - */ -#if HAVE_FULLFSYNC - if( fullSync ){ - rc = fcntl(fd, F_FULLFSYNC, 0); - }else{ - rc = 1; - } - /* If the FULLFSYNC failed, fall back to attempting an fsync(). - ** It shouldn't be possible for fullfsync to fail on the local - ** file system (on OSX), so failure indicates that FULLFSYNC - ** isn't supported for this file system. So, attempt an fsync - ** and (for now) ignore the overhead of a superfluous fcntl call. - ** It'd be better to detect fullfsync support once and avoid - ** the fcntl call every time sync is called. - */ - if( rc ) rc = fsync(fd); - -#elif defined(__APPLE__) - /* fdatasync() on HFS+ doesn't yet flush the file size if it changed correctly - ** so currently we default to the macro that redefines fdatasync to fsync - */ - rc = fsync(fd); -#else - rc = fdatasync(fd); -#endif /* ifdef UNQLITE_NO_SYNC elif HAVE_FULLFSYNC */ - if( rc!= -1 ){ - rc = 0; - } - return rc; -} -/* -** Make sure all writes to a particular file are committed to disk. -** -** If dataOnly==0 then both the file itself and its metadata (file -** size, access time, etc) are synced. If dataOnly!=0 then only the -** file data is synced. -** -** Under Unix, also make sure that the directory entry for the file -** has been created by fsync-ing the directory that contains the file. -** If we do not do this and we encounter a power failure, the directory -** entry for the journal might not exist after we reboot. The next -** SQLite to access the file will not know that the journal exists (because -** the directory entry for the journal was never created) and the transaction -** will not roll back - possibly leading to database corruption. -*/ -static int unixSync(unqlite_file *id, int flags){ - int rc; - unixFile *pFile = (unixFile*)id; - - int isDataOnly = (flags&UNQLITE_SYNC_DATAONLY); - int isFullsync = (flags&0x0F)==UNQLITE_SYNC_FULL; - - rc = full_fsync(pFile->h, isFullsync, isDataOnly); - - if( rc ){ - pFile->lastErrno = errno; - return UNQLITE_IOERR; - } - if( pFile->dirfd>=0 ){ - int err; -#ifndef UNQLITE_DISABLE_DIRSYNC - /* The directory sync is only attempted if full_fsync is - ** turned off or unavailable. If a full_fsync occurred above, - ** then the directory sync is superfluous. - */ - if( (!HAVE_FULLFSYNC || !isFullsync) && full_fsync(pFile->dirfd,0,0) ){ - /* - ** We have received multiple reports of fsync() returning - ** errors when applied to directories on certain file systems. - ** A failed directory sync is not a big deal. So it seems - ** better to ignore the error. Ticket #1657 - */ - /* pFile->lastErrno = errno; */ - /* return UNQLITE_IOERR; */ - } -#endif - err = close(pFile->dirfd); /* Only need to sync once, so close the */ - if( err==0 ){ /* directory when we are done */ - pFile->dirfd = -1; - }else{ - pFile->lastErrno = errno; - rc = UNQLITE_IOERR; - } - } - return rc; -} -/* -** Truncate an open file to a specified size -*/ -static int unixTruncate(unqlite_file *id, sxi64 nByte){ - unixFile *pFile = (unixFile *)id; - int rc; - - rc = ftruncate(pFile->h, (off_t)nByte); - if( rc ){ - pFile->lastErrno = errno; - return UNQLITE_IOERR; - }else{ - return UNQLITE_OK; - } -} -/* -** Determine the current size of a file in bytes -*/ -static int unixFileSize(unqlite_file *id,sxi64 *pSize){ - int rc; - struct stat buf; - - rc = fstat(((unixFile*)id)->h, &buf); - - if( rc!=0 ){ - ((unixFile*)id)->lastErrno = errno; - return UNQLITE_IOERR; - } - *pSize = buf.st_size; - - /* When opening a zero-size database, the findInodeInfo() procedure - ** writes a single byte into that file in order to work around a bug - ** in the OS-X msdos filesystem. In order to avoid problems with upper - ** layers, we need to report this file size as zero even though it is - ** really 1. Ticket #3260. - */ - if( *pSize==1 ) *pSize = 0; - - return UNQLITE_OK; -} -/* -** Return the sector size in bytes of the underlying block device for -** the specified file. This is almost always 512 bytes, but may be -** larger for some devices. -** -** SQLite code assumes this function cannot fail. It also assumes that -** if two files are created in the same file-system directory (i.e. -** a database and its journal file) that the sector size will be the -** same for both. -*/ -static int unixSectorSize(unqlite_file *NotUsed){ - SXUNUSED(NotUsed); - return UNQLITE_DEFAULT_SECTOR_SIZE; -} -/* -** This vector defines all the methods that can operate on an -** unqlite_file for Windows systems. -*/ -static const unqlite_io_methods unixIoMethod = { - 1, /* iVersion */ - unixClose, /* xClose */ - unixRead, /* xRead */ - unixWrite, /* xWrite */ - unixTruncate, /* xTruncate */ - unixSync, /* xSync */ - unixFileSize, /* xFileSize */ - unixLock, /* xLock */ - unixUnlock, /* xUnlock */ - unixCheckReservedLock, /* xCheckReservedLock */ - unixSectorSize, /* xSectorSize */ -}; -/**************************************************************************** -**************************** unqlite_vfs methods **************************** -** -** This division contains the implementation of methods on the -** unqlite_vfs object. -*/ -/* -** Initialize the contents of the unixFile structure pointed to by pId. -*/ -static int fillInUnixFile( - unqlite_vfs *pVfs, /* Pointer to vfs object */ - int h, /* Open file descriptor of file being opened */ - int dirfd, /* Directory file descriptor */ - unqlite_file *pId, /* Write to the unixFile structure here */ - const char *zFilename, /* Name of the file being opened */ - int noLock, /* Omit locking if true */ - int isDelete /* Delete on close if true */ -){ - const unqlite_io_methods *pLockingStyle = &unixIoMethod; - unixFile *pNew = (unixFile *)pId; - int rc = UNQLITE_OK; - - /* Parameter isDelete is only used on vxworks. Express this explicitly - ** here to prevent compiler warnings about unused parameters. - */ - SXUNUSED(isDelete); - SXUNUSED(noLock); - SXUNUSED(pVfs); - - pNew->h = h; - pNew->dirfd = dirfd; - pNew->fileFlags = 0; - pNew->zPath = zFilename; - - unixEnterMutex(); - rc = findInodeInfo(pNew, &pNew->pInode); - if( rc!=UNQLITE_OK ){ - /* If an error occured in findInodeInfo(), close the file descriptor - ** immediately, before releasing the mutex. findInodeInfo() may fail - ** in two scenarios: - ** - ** (a) A call to fstat() failed. - ** (b) A malloc failed. - ** - ** Scenario (b) may only occur if the process is holding no other - ** file descriptors open on the same file. If there were other file - ** descriptors on this file, then no malloc would be required by - ** findInodeInfo(). If this is the case, it is quite safe to close - ** handle h - as it is guaranteed that no posix locks will be released - ** by doing so. - ** - ** If scenario (a) caused the error then things are not so safe. The - ** implicit assumption here is that if fstat() fails, things are in - ** such bad shape that dropping a lock or two doesn't matter much. - */ - close(h); - h = -1; - } - unixLeaveMutex(); - - pNew->lastErrno = 0; - if( rc!=UNQLITE_OK ){ - if( dirfd>=0 ) close(dirfd); /* silent leak if fail, already in error */ - if( h>=0 ) close(h); - }else{ - pNew->pMethod = pLockingStyle; - } - return rc; -} -/* -** Open a file descriptor to the directory containing file zFilename. -** If successful, *pFd is set to the opened file descriptor and -** UNQLITE_OK is returned. If an error occurs, either UNQLITE_NOMEM -** or UNQLITE_CANTOPEN is returned and *pFd is set to an undefined -** value. -** -** If UNQLITE_OK is returned, the caller is responsible for closing -** the file descriptor *pFd using close(). -*/ -static int openDirectory(const char *zFilename, int *pFd){ - sxu32 ii; - int fd = -1; - char zDirname[MAX_PATHNAME+1]; - sxu32 n; - n = Systrcpy(zDirname,sizeof(zDirname),zFilename,0); - for(ii=n; ii>1 && zDirname[ii]!='/'; ii--); - if( ii>0 ){ - zDirname[ii] = '\0'; - fd = open(zDirname, O_RDONLY|O_BINARY, 0); - if( fd>=0 ){ -#ifdef FD_CLOEXEC - fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); -#endif - } - } - *pFd = fd; - return (fd>=0?UNQLITE_OK: UNQLITE_IOERR ); -} -/* -** Search for an unused file descriptor that was opened on the database -** file (not a journal or master-journal file) identified by pathname -** zPath with UNQLITE_OPEN_XXX flags matching those passed as the second -** argument to this function. -** -** Such a file descriptor may exist if a database connection was closed -** but the associated file descriptor could not be closed because some -** other file descriptor open on the same file is holding a file-lock. -** Refer to comments in the unixClose() function and the lengthy comment -** describing "Posix Advisory Locking" at the start of this file for -** further details. Also, ticket #4018. -** -** If a suitable file descriptor is found, then it is returned. If no -** such file descriptor is located, -1 is returned. -*/ -static UnixUnusedFd *findReusableFd(const char *zPath, int flags){ - UnixUnusedFd *pUnused = 0; - struct stat sStat; /* Results of stat() call */ - /* A stat() call may fail for various reasons. If this happens, it is - ** almost certain that an open() call on the same path will also fail. - ** For this reason, if an error occurs in the stat() call here, it is - ** ignored and -1 is returned. The caller will try to open a new file - ** descriptor on the same path, fail, and return an error to SQLite. - ** - ** Even if a subsequent open() call does succeed, the consequences of - ** not searching for a resusable file descriptor are not dire. */ - if( 0==stat(zPath, &sStat) ){ - unixInodeInfo *pInode; - - unixEnterMutex(); - pInode = inodeList; - while( pInode && (pInode->fileId.dev!=sStat.st_dev - || pInode->fileId.ino!=sStat.st_ino) ){ - pInode = pInode->pNext; - } - if( pInode ){ - UnixUnusedFd **pp; - for(pp=&pInode->pUnused; *pp && (*pp)->flags!=flags; pp=&((*pp)->pNext)); - pUnused = *pp; - if( pUnused ){ - *pp = pUnused->pNext; - } - } - unixLeaveMutex(); - } - return pUnused; -} -/* -** This function is called by unixOpen() to determine the unix permissions -** to create new files with. If no error occurs, then UNQLITE_OK is returned -** and a value suitable for passing as the third argument to open(2) is -** written to *pMode. If an IO error occurs, an SQLite error code is -** returned and the value of *pMode is not modified. -** -** If the file being opened is a temporary file, it is always created with -** the octal permissions 0600 (read/writable by owner only). If the file -** is a database or master journal file, it is created with the permissions -** mask UNQLITE_DEFAULT_FILE_PERMISSIONS. -** -** Finally, if the file being opened is a WAL or regular journal file, then -** this function queries the file-system for the permissions on the -** corresponding database file and sets *pMode to this value. Whenever -** possible, WAL and journal files are created using the same permissions -** as the associated database file. -*/ -static int findCreateFileMode( - const char *zPath, /* Path of file (possibly) being created */ - int flags, /* Flags passed as 4th argument to xOpen() */ - mode_t *pMode /* OUT: Permissions to open file with */ -){ - int rc = UNQLITE_OK; /* Return Code */ - if( flags & UNQLITE_OPEN_TEMP_DB ){ - *pMode = 0600; - SXUNUSED(zPath); - }else{ - *pMode = UNQLITE_DEFAULT_FILE_PERMISSIONS; - } - return rc; -} -/* -** Open the file zPath. -** -** Previously, the SQLite OS layer used three functions in place of this -** one: -** -** unqliteOsOpenReadWrite(); -** unqliteOsOpenReadOnly(); -** unqliteOsOpenExclusive(); -** -** These calls correspond to the following combinations of flags: -** -** ReadWrite() -> (READWRITE | CREATE) -** ReadOnly() -> (READONLY) -** OpenExclusive() -> (READWRITE | CREATE | EXCLUSIVE) -** -** The old OpenExclusive() accepted a boolean argument - "delFlag". If -** true, the file was configured to be automatically deleted when the -** file handle closed. To achieve the same effect using this new -** interface, add the DELETEONCLOSE flag to those specified above for -** OpenExclusive(). -*/ -static int unixOpen( - unqlite_vfs *pVfs, /* The VFS for which this is the xOpen method */ - const char *zPath, /* Pathname of file to be opened */ - unqlite_file *pFile, /* The file descriptor to be filled in */ - unsigned int flags /* Input flags to control the opening */ -){ - unixFile *p = (unixFile *)pFile; - int fd = -1; /* File descriptor returned by open() */ - int dirfd = -1; /* Directory file descriptor */ - int openFlags = 0; /* Flags to pass to open() */ - int noLock; /* True to omit locking primitives */ - int rc = UNQLITE_OK; /* Function Return Code */ - UnixUnusedFd *pUnused; - int isExclusive = (flags & UNQLITE_OPEN_EXCLUSIVE); - int isDelete = (flags & UNQLITE_OPEN_TEMP_DB); - int isCreate = (flags & UNQLITE_OPEN_CREATE); - int isReadonly = (flags & UNQLITE_OPEN_READONLY); - int isReadWrite = (flags & UNQLITE_OPEN_READWRITE); - /* If creating a master or main-file journal, this function will open - ** a file-descriptor on the directory too. The first time unixSync() - ** is called the directory file descriptor will be fsync()ed and close()d. - */ - int isOpenDirectory = isCreate; - const char *zName = zPath; - - SyZero(p,sizeof(unixFile)); - - pUnused = findReusableFd(zName, flags); - if( pUnused ){ - fd = pUnused->fd; - }else{ - pUnused = unqlite_malloc(sizeof(*pUnused)); - if( !pUnused ){ - return UNQLITE_NOMEM; - } - } - p->pUnused = pUnused; - - /* Determine the value of the flags parameter passed to POSIX function - ** open(). These must be calculated even if open() is not called, as - ** they may be stored as part of the file handle and used by the - ** 'conch file' locking functions later on. */ - if( isReadonly ) openFlags |= O_RDONLY; - if( isReadWrite ) openFlags |= O_RDWR; - if( isCreate ) openFlags |= O_CREAT; - if( isExclusive ) openFlags |= (O_EXCL|O_NOFOLLOW); - openFlags |= (O_LARGEFILE|O_BINARY); - - if( fd<0 ){ - mode_t openMode; /* Permissions to create file with */ - rc = findCreateFileMode(zName, flags, &openMode); - if( rc!=UNQLITE_OK ){ - return rc; - } - fd = open(zName, openFlags, openMode); - if( fd<0 ){ - rc = UNQLITE_IOERR; - goto open_finished; - } - } - - if( p->pUnused ){ - p->pUnused->fd = fd; - p->pUnused->flags = flags; - } - - if( isDelete ){ - unlink(zName); - } - - if( isOpenDirectory ){ - rc = openDirectory(zPath, &dirfd); - if( rc!=UNQLITE_OK ){ - /* It is safe to close fd at this point, because it is guaranteed not - ** to be open on a database file. If it were open on a database file, - ** it would not be safe to close as this would release any locks held - ** on the file by this process. */ - close(fd); /* silently leak if fail, already in error */ - goto open_finished; - } - } - -#ifdef FD_CLOEXEC - fcntl(fd, F_SETFD, fcntl(fd, F_GETFD, 0) | FD_CLOEXEC); -#endif - - noLock = 0; - -#if defined(__APPLE__) - struct statfs fsInfo; - if( fstatfs(fd, &fsInfo) == -1 ){ - ((unixFile*)pFile)->lastErrno = errno; - if( dirfd>=0 ) close(dirfd); /* silently leak if fail, in error */ - close(fd); /* silently leak if fail, in error */ - return UNQLITE_IOERR; - } - if (0 == SyStrncmp("msdos", fsInfo.f_fstypename, 5)) { - ((unixFile*)pFile)->fsFlags |= UNQLITE_FSFLAGS_IS_MSDOS; - } -#endif - - rc = fillInUnixFile(pVfs, fd, dirfd, pFile, zPath, noLock, isDelete); -open_finished: - if( rc!=UNQLITE_OK ){ - unqlite_free(p->pUnused); - } - return rc; -} -/* -** Delete the file at zPath. If the dirSync argument is true, fsync() -** the directory after deleting the file. -*/ -static int unixDelete( - unqlite_vfs *NotUsed, /* VFS containing this as the xDelete method */ - const char *zPath, /* Name of file to be deleted */ - int dirSync /* If true, fsync() directory after deleting file */ -){ - int rc = UNQLITE_OK; - SXUNUSED(NotUsed); - - if( unlink(zPath)==(-1) && errno!=ENOENT ){ - return UNQLITE_IOERR; - } -#ifndef UNQLITE_DISABLE_DIRSYNC - if( dirSync ){ - int fd; - rc = openDirectory(zPath, &fd); - if( rc==UNQLITE_OK ){ - if( fsync(fd) ) - { - rc = UNQLITE_IOERR; - } - if( close(fd) && !rc ){ - rc = UNQLITE_IOERR; - } - } - } -#endif - return rc; -} -/* -** Sleep for a little while. Return the amount of time slept. -** The argument is the number of microseconds we want to sleep. -** The return value is the number of microseconds of sleep actually -** requested from the underlying operating system, a number which -** might be greater than or equal to the argument, but not less -** than the argument. -*/ -static int unixSleep(unqlite_vfs *NotUsed, int microseconds) -{ -#if defined(HAVE_USLEEP) && HAVE_USLEEP - usleep(microseconds); - SXUNUSED(NotUsed); - return microseconds; -#else - int seconds = (microseconds+999999)/1000000; - SXUNUSED(NotUsed); - sleep(seconds); - return seconds*1000000; -#endif -} -/* - * Export the current system time. - */ -static int unixCurrentTime(unqlite_vfs *pVfs,Sytm *pOut) -{ - struct tm *pTm; - time_t tt; - SXUNUSED(pVfs); - time(&tt); - pTm = gmtime(&tt); - if( pTm ){ /* Yes, it can fail */ - STRUCT_TM_TO_SYTM(pTm,pOut); - } - return UNQLITE_OK; -} -/* -** Test the existance of or access permissions of file zPath. The -** test performed depends on the value of flags: -** -** UNQLITE_ACCESS_EXISTS: Return 1 if the file exists -** UNQLITE_ACCESS_READWRITE: Return 1 if the file is read and writable. -** UNQLITE_ACCESS_READONLY: Return 1 if the file is readable. -** -** Otherwise return 0. -*/ -static int unixAccess( - unqlite_vfs *NotUsed, /* The VFS containing this xAccess method */ - const char *zPath, /* Path of the file to examine */ - int flags, /* What do we want to learn about the zPath file? */ - int *pResOut /* Write result boolean here */ -){ - int amode = 0; - SXUNUSED(NotUsed); - switch( flags ){ - case UNQLITE_ACCESS_EXISTS: - amode = F_OK; - break; - case UNQLITE_ACCESS_READWRITE: - amode = W_OK|R_OK; - break; - case UNQLITE_ACCESS_READ: - amode = R_OK; - break; - default: - /* Can't happen */ - break; - } - *pResOut = (access(zPath, amode)==0); - if( flags==UNQLITE_ACCESS_EXISTS && *pResOut ){ - struct stat buf; - if( 0==stat(zPath, &buf) && buf.st_size==0 ){ - *pResOut = 0; - } - } - return UNQLITE_OK; -} -/* -** Turn a relative pathname into a full pathname. The relative path -** is stored as a nul-terminated string in the buffer pointed to by -** zPath. -** -** zOut points to a buffer of at least unqlite_vfs.mxPathname bytes -** (in this case, MAX_PATHNAME bytes). The full-path is written to -** this buffer before returning. -*/ -static int unixFullPathname( - unqlite_vfs *pVfs, /* Pointer to vfs object */ - const char *zPath, /* Possibly relative input path */ - int nOut, /* Size of output buffer in bytes */ - char *zOut /* Output buffer */ -){ - if( zPath[0]=='/' ){ - Systrcpy(zOut,(sxu32)nOut,zPath,0); - SXUNUSED(pVfs); - }else{ - sxu32 nCwd; - zOut[nOut-1] = '\0'; - if( getcwd(zOut, nOut-1)==0 ){ - return UNQLITE_IOERR; - } - nCwd = SyStrlen(zOut); - SyBufferFormat(&zOut[nCwd],(sxu32)nOut-nCwd,"/%s",zPath); - } - return UNQLITE_OK; -} -/* - * Export the Unix Vfs. - */ -UNQLITE_PRIVATE const unqlite_vfs * unqliteExportBuiltinVfs(void) -{ - static const unqlite_vfs sUnixvfs = { - "Unix", /* Vfs name */ - 1, /* Vfs structure version */ - sizeof(unixFile), /* szOsFile */ - MAX_PATHNAME, /* mxPathName */ - unixOpen, /* xOpen */ - unixDelete, /* xDelete */ - unixAccess, /* xAccess */ - unixFullPathname, /* xFullPathname */ - 0, /* xTmp */ - unixSleep, /* xSleep */ - unixCurrentTime, /* xCurrentTime */ - 0, /* xGetLastError */ - }; - return &sUnixvfs; -} - -#endif /* __UNIXES__ */ - -/* - * ---------------------------------------------------------- - * File: os_win.c - * MD5: ab70fb386c21b39a08b0eb776a8391ab - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: os_win.c v1.2 Win7 2012-11-10 12:10 devel $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* Omit the whole layer from the build if compiling for platforms other than Windows */ -#ifdef __WINNT__ -/* This file contains code that is specific to windows. (Mostly SQLite3 source tree) */ -#include -/* -** Some microsoft compilers lack this definition. -*/ -#ifndef INVALID_FILE_ATTRIBUTES -# define INVALID_FILE_ATTRIBUTES ((DWORD)-1) -#endif -/* -** WinCE lacks native support for file locking so we have to fake it -** with some code of our own. -*/ -#ifdef __WIN_CE__ -typedef struct winceLock { - int nReaders; /* Number of reader locks obtained */ - BOOL bPending; /* Indicates a pending lock has been obtained */ - BOOL bReserved; /* Indicates a reserved lock has been obtained */ - BOOL bExclusive; /* Indicates an exclusive lock has been obtained */ -} winceLock; -#define AreFileApisANSI() 1 -#define FormatMessageW(a,b,c,d,e,f,g) 0 -#endif - -/* -** The winFile structure is a subclass of unqlite_file* specific to the win32 -** portability layer. -*/ -typedef struct winFile winFile; -struct winFile { - const unqlite_io_methods *pMethod; /*** Must be first ***/ - unqlite_vfs *pVfs; /* The VFS used to open this file */ - HANDLE h; /* Handle for accessing the file */ - sxu8 locktype; /* Type of lock currently held on this file */ - short sharedLockByte; /* Randomly chosen byte used as a shared lock */ - DWORD lastErrno; /* The Windows errno from the last I/O error */ - DWORD sectorSize; /* Sector size of the device file is on */ - int szChunk; /* Chunk size */ -#ifdef __WIN_CE__ - WCHAR *zDeleteOnClose; /* Name of file to delete when closing */ - HANDLE hMutex; /* Mutex used to control access to shared lock */ - HANDLE hShared; /* Shared memory segment used for locking */ - winceLock local; /* Locks obtained by this instance of winFile */ - winceLock *shared; /* Global shared lock memory for the file */ -#endif -}; -/* -** Convert a UTF-8 string to microsoft unicode (UTF-16?). -** -** Space to hold the returned string is obtained from HeapAlloc(). -*/ -static WCHAR *utf8ToUnicode(const char *zFilename){ - int nChar; - WCHAR *zWideFilename; - - nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, 0, 0); - zWideFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nChar*sizeof(zWideFilename[0]) ); - if( zWideFilename==0 ){ - return 0; - } - nChar = MultiByteToWideChar(CP_UTF8, 0, zFilename, -1, zWideFilename, nChar); - if( nChar==0 ){ - HeapFree(GetProcessHeap(),0,zWideFilename); - zWideFilename = 0; - } - return zWideFilename; -} - -/* -** Convert microsoft unicode to UTF-8. Space to hold the returned string is -** obtained from malloc(). -*/ -static char *unicodeToUtf8(const WCHAR *zWideFilename){ - int nByte; - char *zFilename; - - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, 0, 0, 0, 0); - zFilename = (char *)HeapAlloc(GetProcessHeap(),0,nByte ); - if( zFilename==0 ){ - return 0; - } - nByte = WideCharToMultiByte(CP_UTF8, 0, zWideFilename, -1, zFilename, nByte, - 0, 0); - if( nByte == 0 ){ - HeapFree(GetProcessHeap(),0,zFilename); - zFilename = 0; - } - return zFilename; -} - -/* -** Convert an ansi string to microsoft unicode, based on the -** current codepage settings for file apis. -** -** Space to hold the returned string is obtained -** from malloc. -*/ -static WCHAR *mbcsToUnicode(const char *zFilename){ - int nByte; - WCHAR *zMbcsFilename; - int codepage = AreFileApisANSI() ? CP_ACP : CP_OEMCP; - - nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, 0,0)*sizeof(WCHAR); - zMbcsFilename = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nByte*sizeof(zMbcsFilename[0]) ); - if( zMbcsFilename==0 ){ - return 0; - } - nByte = MultiByteToWideChar(codepage, 0, zFilename, -1, zMbcsFilename, nByte); - if( nByte==0 ){ - HeapFree(GetProcessHeap(),0,zMbcsFilename); - zMbcsFilename = 0; - } - return zMbcsFilename; -} -/* -** Convert multibyte character string to UTF-8. Space to hold the -** returned string is obtained from malloc(). -*/ -char *unqlite_win32_mbcs_to_utf8(const char *zFilename){ - char *zFilenameUtf8; - WCHAR *zTmpWide; - - zTmpWide = mbcsToUnicode(zFilename); - if( zTmpWide==0 ){ - return 0; - } - zFilenameUtf8 = unicodeToUtf8(zTmpWide); - HeapFree(GetProcessHeap(),0,zTmpWide); - return zFilenameUtf8; -} -/* -** Some microsoft compilers lack this definition. -*/ -#ifndef INVALID_SET_FILE_POINTER -# define INVALID_SET_FILE_POINTER ((DWORD)-1) -#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. -*/ -static int seekWinFile(winFile *pFile, unqlite_int64 iOffset){ - LONG upperBits; /* Most sig. 32 bits of new offset */ - LONG lowerBits; /* Least sig. 32 bits of new offset */ - DWORD dwRet; /* Value returned by SetFilePointer() */ - - upperBits = (LONG)((iOffset>>32) & 0x7fffffff); - lowerBits = (LONG)(iOffset & 0xffffffff); - - /* 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 occured, it is also necessary to call - ** GetLastError(). - */ - dwRet = SetFilePointer(pFile->h, lowerBits, &upperBits, FILE_BEGIN); - if( (dwRet==INVALID_SET_FILE_POINTER && GetLastError()!=NO_ERROR) ){ - pFile->lastErrno = GetLastError(); - return 1; - } - return 0; -} -/* -** Close a file. -** -** It is reported that an attempt to close a handle might sometimes -** fail. This is a very unreasonable result, but windows is notorious -** for being unreasonable so I do not doubt that it might happen. If -** the close fails, we pause for 100 milliseconds and try again. As -** many as MX_CLOSE_ATTEMPT attempts to close the handle are made before -** giving up and returning an error. -*/ -#define MX_CLOSE_ATTEMPT 3 -static int winClose(unqlite_file *id) -{ - int rc, cnt = 0; - winFile *pFile = (winFile*)id; - do{ - rc = CloseHandle(pFile->h); - }while( rc==0 && ++cnt < MX_CLOSE_ATTEMPT && (Sleep(100), 1) ); - - return rc ? UNQLITE_OK : UNQLITE_IOERR; -} -/* -** Read data from a file into a buffer. Return UNQLITE_OK if all -** bytes were read successfully and UNQLITE_IOERR if anything goes -** wrong. -*/ -static int winRead( - unqlite_file *id, /* File to read from */ - void *pBuf, /* Write content into this buffer */ - unqlite_int64 amt, /* Number of bytes to read */ - unqlite_int64 offset /* Begin reading at this offset */ -){ - winFile *pFile = (winFile*)id; /* file handle */ - DWORD nRead; /* Number of bytes actually read from file */ - - if( seekWinFile(pFile, offset) ){ - return UNQLITE_FULL; - } - if( !ReadFile(pFile->h, pBuf, (DWORD)amt, &nRead, 0) ){ - pFile->lastErrno = GetLastError(); - return UNQLITE_IOERR; - } - if( nRead<(DWORD)amt ){ - /* Unread parts of the buffer must be zero-filled */ - SyZero(&((char*)pBuf)[nRead],(sxu32)(amt-nRead)); - return UNQLITE_IOERR; - } - - return UNQLITE_OK; -} - -/* -** Write data from a buffer into a file. Return UNQLITE_OK on success -** or some other error code on failure. -*/ -static int winWrite( - unqlite_file *id, /* File to write into */ - const void *pBuf, /* The bytes to be written */ - unqlite_int64 amt, /* Number of bytes to write */ - unqlite_int64 offset /* Offset into the file to begin writing at */ -){ - int rc; /* True if error has occured, else false */ - winFile *pFile = (winFile*)id; /* File handle */ - - rc = seekWinFile(pFile, offset); - if( rc==0 ){ - sxu8 *aRem = (sxu8 *)pBuf; /* Data yet to be written */ - unqlite_int64 nRem = amt; /* Number of bytes yet to be written */ - DWORD nWrite; /* Bytes written by each WriteFile() call */ - - while( nRem>0 && WriteFile(pFile->h, aRem, (DWORD)nRem, &nWrite, 0) && nWrite>0 ){ - aRem += nWrite; - nRem -= nWrite; - } - if( nRem>0 ){ - pFile->lastErrno = GetLastError(); - rc = 1; - } - } - if( rc ){ - if( pFile->lastErrno==ERROR_HANDLE_DISK_FULL ){ - return UNQLITE_FULL; - } - return UNQLITE_IOERR; - } - return UNQLITE_OK; -} - -/* -** Truncate an open file to a specified size -*/ -static int winTruncate(unqlite_file *id, unqlite_int64 nByte){ - winFile *pFile = (winFile*)id; /* File handle object */ - int rc = UNQLITE_OK; /* Return code for this function */ - - - /* If the user has configured a chunk-size for this file, truncate the - ** file so that it consists of an integer number of chunks (i.e. the - ** actual file size after the operation may be larger than the requested - ** size). - */ - if( pFile->szChunk ){ - nByte = ((nByte + pFile->szChunk - 1)/pFile->szChunk) * pFile->szChunk; - } - - /* SetEndOfFile() returns non-zero when successful, or zero when it fails. */ - if( seekWinFile(pFile, nByte) ){ - rc = UNQLITE_IOERR; - }else if( 0==SetEndOfFile(pFile->h) ){ - pFile->lastErrno = GetLastError(); - rc = UNQLITE_IOERR; - } - return rc; -} -/* -** Make sure all writes to a particular file are committed to disk. -*/ -static int winSync(unqlite_file *id, int flags){ - winFile *pFile = (winFile*)id; - SXUNUSED(flags); /* MSVC warning */ - if( FlushFileBuffers(pFile->h) ){ - return UNQLITE_OK; - }else{ - pFile->lastErrno = GetLastError(); - return UNQLITE_IOERR; - } -} -/* -** Determine the current size of a file in bytes -*/ -static int winFileSize(unqlite_file *id, unqlite_int64 *pSize){ - DWORD upperBits; - DWORD lowerBits; - winFile *pFile = (winFile*)id; - DWORD error; - lowerBits = GetFileSize(pFile->h, &upperBits); - if( (lowerBits == INVALID_FILE_SIZE) - && ((error = GetLastError()) != NO_ERROR) ) - { - pFile->lastErrno = error; - return UNQLITE_IOERR; - } - *pSize = (((unqlite_int64)upperBits)<<32) + lowerBits; - return UNQLITE_OK; -} -/* -** LOCKFILE_FAIL_IMMEDIATELY is undefined on some Windows systems. -*/ -#ifndef LOCKFILE_FAIL_IMMEDIATELY -# define LOCKFILE_FAIL_IMMEDIATELY 1 -#endif - -/* -** Acquire a reader lock. -*/ -static int getReadLock(winFile *pFile){ - int res; - OVERLAPPED ovlp; - ovlp.Offset = SHARED_FIRST; - ovlp.OffsetHigh = 0; - ovlp.hEvent = 0; - res = LockFileEx(pFile->h, LOCKFILE_FAIL_IMMEDIATELY,0, SHARED_SIZE, 0, &ovlp); - if( res == 0 ){ - pFile->lastErrno = GetLastError(); - } - return res; -} -/* -** Undo a readlock -*/ -static int unlockReadLock(winFile *pFile){ - int res; - res = UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( res == 0 ){ - pFile->lastErrno = GetLastError(); - } - return res; -} -/* -** Lock the file with the lock specified by parameter locktype - one -** of the following: -** -** (1) SHARED_LOCK -** (2) RESERVED_LOCK -** (3) PENDING_LOCK -** (4) EXCLUSIVE_LOCK -** -** Sometimes when requesting one lock state, additional lock states -** are inserted in between. The locking might fail on one of the later -** transitions leaving the lock state different from what it started but -** still short of its goal. The following chart shows the allowed -** transitions and the inserted intermediate states: -** -** UNLOCKED -> SHARED -** SHARED -> RESERVED -** SHARED -> (PENDING) -> EXCLUSIVE -** RESERVED -> (PENDING) -> EXCLUSIVE -** PENDING -> EXCLUSIVE -** -** This routine will only increase a lock. The winUnlock() routine -** erases all locks at once and returns us immediately to locking level 0. -** It is not possible to lower the locking level one step at a time. You -** must go straight to locking level 0. -*/ -static int winLock(unqlite_file *id, int locktype){ - int rc = UNQLITE_OK; /* Return code from subroutines */ - int res = 1; /* Result of a windows lock call */ - int newLocktype; /* Set pFile->locktype to this value before exiting */ - int gotPendingLock = 0;/* True if we acquired a PENDING lock this time */ - winFile *pFile = (winFile*)id; - DWORD error = NO_ERROR; - - /* If there is already a lock of this type or more restrictive on the - ** OsFile, do nothing. - */ - if( pFile->locktype>=locktype ){ - return UNQLITE_OK; - } - - /* Make sure the locking sequence is correct - assert( pFile->locktype!=NO_LOCK || locktype==SHARED_LOCK ); - 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 - ** 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)) - ){ - int cnt = 3; - while( cnt-->0 && (res = LockFile(pFile->h, PENDING_BYTE, 0, 1, 0))==0 ){ - /* Try 3 times to get the pending lock. The pending lock might be - ** held by another reader process who will release it momentarily. - */ - Sleep(1); - } - gotPendingLock = res; - if( !res ){ - error = GetLastError(); - } - } - - /* Acquire a shared lock - */ - if( locktype==SHARED_LOCK && res ){ - /* assert( pFile->locktype==NO_LOCK ); */ - res = getReadLock(pFile); - if( res ){ - newLocktype = SHARED_LOCK; - }else{ - error = GetLastError(); - } - } - - /* Acquire a RESERVED lock - */ - if( locktype==RESERVED_LOCK && res ){ - /* assert( pFile->locktype==SHARED_LOCK ); */ - res = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); - if( res ){ - newLocktype = RESERVED_LOCK; - }else{ - error = GetLastError(); - } - } - - /* Acquire a PENDING lock - */ - if( locktype==EXCLUSIVE_LOCK && res ){ - newLocktype = PENDING_LOCK; - gotPendingLock = 0; - } - - /* Acquire an EXCLUSIVE lock - */ - if( locktype==EXCLUSIVE_LOCK && res ){ - /* assert( pFile->locktype>=SHARED_LOCK ); */ - res = unlockReadLock(pFile); - res = LockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( res ){ - newLocktype = EXCLUSIVE_LOCK; - }else{ - error = GetLastError(); - getReadLock(pFile); - } - } - - /* If we are holding a PENDING lock that ought to be released, then - ** release it now. - */ - if( gotPendingLock && locktype==SHARED_LOCK ){ - UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); - } - - /* Update the state of the lock has held in the file descriptor then - ** return the appropriate result code. - */ - if( res ){ - rc = UNQLITE_OK; - }else{ - pFile->lastErrno = error; - rc = UNQLITE_BUSY; - } - pFile->locktype = (sxu8)newLocktype; - return rc; -} -/* -** 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, return -** non-zero, otherwise zero. -*/ -static int winCheckReservedLock(unqlite_file *id, int *pResOut){ - int rc; - winFile *pFile = (winFile*)id; - if( pFile->locktype>=RESERVED_LOCK ){ - rc = 1; - }else{ - rc = LockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); - if( rc ){ - UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); - } - rc = !rc; - } - *pResOut = rc; - return UNQLITE_OK; -} -/* -** Lower the locking level on file descriptor id to locktype. locktype -** must be either NO_LOCK or SHARED_LOCK. -** -** If the locking level of the file descriptor is already at or below -** the requested locking level, this routine is a no-op. -** -** It is not possible for this routine to fail if the second argument -** is NO_LOCK. If the second argument is SHARED_LOCK then this routine -** might return UNQLITE_IOERR; -*/ -static int winUnlock(unqlite_file *id, int locktype){ - int type; - winFile *pFile = (winFile*)id; - int rc = UNQLITE_OK; - - type = pFile->locktype; - if( type>=EXCLUSIVE_LOCK ){ - UnlockFile(pFile->h, SHARED_FIRST, 0, SHARED_SIZE, 0); - if( locktype==SHARED_LOCK && !getReadLock(pFile) ){ - /* This should never happen. We should always be able to - ** reacquire the read lock */ - rc = UNQLITE_IOERR; - } - } - if( type>=RESERVED_LOCK ){ - UnlockFile(pFile->h, RESERVED_BYTE, 0, 1, 0); - } - if( locktype==NO_LOCK && type>=SHARED_LOCK ){ - unlockReadLock(pFile); - } - if( type>=PENDING_LOCK ){ - UnlockFile(pFile->h, PENDING_BYTE, 0, 1, 0); - } - pFile->locktype = (sxu8)locktype; - return rc; -} -/* -** Return the sector size in bytes of the underlying block device for -** the specified file. This is almost always 512 bytes, but may be -** larger for some devices. -** -*/ -static int winSectorSize(unqlite_file *id){ - return (int)(((winFile*)id)->sectorSize); -} -/* -** This vector defines all the methods that can operate on an -** unqlite_file for Windows systems. -*/ -static const unqlite_io_methods winIoMethod = { - 1, /* iVersion */ - winClose, /* xClose */ - winRead, /* xRead */ - winWrite, /* xWrite */ - winTruncate, /* xTruncate */ - winSync, /* xSync */ - winFileSize, /* xFileSize */ - winLock, /* xLock */ - winUnlock, /* xUnlock */ - winCheckReservedLock, /* xCheckReservedLock */ - winSectorSize, /* xSectorSize */ -}; -/* - * Windows VFS Methods. - */ -/* -** 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 *convertUtf8Filename(const char *zFilename) -{ - void *zConverted; - zConverted = utf8ToUnicode(zFilename); - /* caller will handle out of memory */ - return zConverted; -} -/* -** Delete the named file. -** -** Note that windows does not allow a file to be deleted if some other -** process has it open. Sometimes a virus scanner or indexing program -** will open a journal file shortly after it is created in order to do -** whatever it does. While this other process is holding the -** file open, we will be unable to delete it. To work around this -** problem, we delay 100 milliseconds and try to delete again. Up -** to MX_DELETION_ATTEMPTs deletion attempts are run before giving -** up and returning an error. -*/ -#define MX_DELETION_ATTEMPTS 5 -static int winDelete( - unqlite_vfs *pVfs, /* Not used on win32 */ - const char *zFilename, /* Name of file to delete */ - int syncDir /* Not used on win32 */ -){ - int cnt = 0; - DWORD rc; - DWORD error = 0; - void *zConverted; - zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - SXUNUSED(pVfs); - SXUNUSED(syncDir); - return UNQLITE_NOMEM; - } - do{ - DeleteFileW((LPCWSTR)zConverted); - }while( ( ((rc = GetFileAttributesW((LPCWSTR)zConverted)) != INVALID_FILE_ATTRIBUTES) - || ((error = GetLastError()) == ERROR_ACCESS_DENIED)) - && (++cnt < MX_DELETION_ATTEMPTS) - && (Sleep(100), 1) - ); - HeapFree(GetProcessHeap(),0,zConverted); - - return ( (rc == INVALID_FILE_ATTRIBUTES) - && (error == ERROR_FILE_NOT_FOUND)) ? UNQLITE_OK : UNQLITE_IOERR; -} -/* -** Check the existance and status of a file. -*/ -static int winAccess( - unqlite_vfs *pVfs, /* Not used */ - const char *zFilename, /* Name of file to check */ - int flags, /* Type of test to make on this file */ - int *pResOut /* OUT: Result */ -){ - WIN32_FILE_ATTRIBUTE_DATA sAttrData; - DWORD attr; - int rc = 0; - void *zConverted; - SXUNUSED(pVfs); - - zConverted = convertUtf8Filename(zFilename); - if( zConverted==0 ){ - return UNQLITE_NOMEM; - } - SyZero(&sAttrData,sizeof(sAttrData)); - if( GetFileAttributesExW((WCHAR*)zConverted, - GetFileExInfoStandard, - &sAttrData) ){ - /* For an UNQLITE_ACCESS_EXISTS query, treat a zero-length file - ** as if it does not exist. - */ - if( flags==UNQLITE_ACCESS_EXISTS - && sAttrData.nFileSizeHigh==0 - && sAttrData.nFileSizeLow==0 ){ - attr = INVALID_FILE_ATTRIBUTES; - }else{ - attr = sAttrData.dwFileAttributes; - } - }else{ - if( GetLastError()!=ERROR_FILE_NOT_FOUND ){ - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_IOERR; - }else{ - attr = INVALID_FILE_ATTRIBUTES; - } - } - HeapFree(GetProcessHeap(),0,zConverted); - switch( flags ){ - case UNQLITE_ACCESS_READWRITE: - rc = (attr & FILE_ATTRIBUTE_READONLY)==0; - break; - case UNQLITE_ACCESS_READ: - case UNQLITE_ACCESS_EXISTS: - default: - rc = attr!=INVALID_FILE_ATTRIBUTES; - break; - } - *pResOut = rc; - return UNQLITE_OK; -} -/* -** Turn a relative pathname into a full pathname. Write the full -** pathname into zOut[]. zOut[] will be at least pVfs->mxPathname -** bytes in size. -*/ -static int winFullPathname( - unqlite_vfs *pVfs, /* Pointer to vfs object */ - const char *zRelative, /* Possibly relative input path */ - int nFull, /* Size of output buffer in bytes */ - char *zFull /* Output buffer */ -){ - int nByte; - void *zConverted; - WCHAR *zTemp; - char *zOut; - SXUNUSED(nFull); - zConverted = convertUtf8Filename(zRelative); - if( zConverted == 0 ){ - return UNQLITE_NOMEM; - } - nByte = GetFullPathNameW((WCHAR*)zConverted, 0, 0, 0) + 3; - zTemp = (WCHAR *)HeapAlloc(GetProcessHeap(),0,nByte*sizeof(zTemp[0]) ); - if( zTemp==0 ){ - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_NOMEM; - } - GetFullPathNameW((WCHAR*)zConverted, nByte, zTemp, 0); - HeapFree(GetProcessHeap(),0,zConverted); - zOut = unicodeToUtf8(zTemp); - HeapFree(GetProcessHeap(),0,zTemp); - if( zOut == 0 ){ - return UNQLITE_NOMEM; - } - Systrcpy(zFull,(sxu32)pVfs->mxPathname,zOut,0); - HeapFree(GetProcessHeap(),0,zOut); - return UNQLITE_OK; -} -/* -** Get the sector size of the device used to store -** file. -*/ -static int getSectorSize( - unqlite_vfs *pVfs, - const char *zRelative /* UTF-8 file name */ -){ - DWORD bytesPerSector = UNQLITE_DEFAULT_SECTOR_SIZE; - char zFullpath[MAX_PATH+1]; - int rc; - DWORD dwRet = 0; - DWORD dwDummy; - /* - ** We need to get the full path name of the file - ** to get the drive letter to look up the sector - ** size. - */ - rc = winFullPathname(pVfs, zRelative, MAX_PATH, zFullpath); - if( rc == UNQLITE_OK ) - { - void *zConverted = convertUtf8Filename(zFullpath); - if( zConverted ){ - /* trim path to just drive reference */ - WCHAR *p = (WCHAR *)zConverted; - for(;*p;p++){ - if( *p == '\\' ){ - *p = '\0'; - break; - } - } - dwRet = GetDiskFreeSpaceW((WCHAR*)zConverted, - &dwDummy, - &bytesPerSector, - &dwDummy, - &dwDummy); - HeapFree(GetProcessHeap(),0,zConverted); - } - if( !dwRet ){ - bytesPerSector = UNQLITE_DEFAULT_SECTOR_SIZE; - } - } - return (int) bytesPerSector; -} -/* -** Sleep for a little while. Return the amount of time slept. -*/ -static int winSleep(unqlite_vfs *pVfs, int microsec){ - Sleep((microsec+999)/1000); - SXUNUSED(pVfs); - return ((microsec+999)/1000)*1000; -} -/* - * Export the current system time. - */ -static int winCurrentTime(unqlite_vfs *pVfs,Sytm *pOut) -{ - SYSTEMTIME sSys; - SXUNUSED(pVfs); - GetSystemTime(&sSys); - SYSTEMTIME_TO_SYTM(&sSys,pOut); - return UNQLITE_OK; -} -/* -** The idea is that this function works like a combination of -** GetLastError() and FormatMessage() on windows (or errno and -** strerror_r() on unix). After an error is returned by an OS -** function, UnQLite calls this function with zBuf pointing to -** a buffer of nBuf bytes. The OS layer should populate the -** buffer with a nul-terminated UTF-8 encoded error message -** describing the last IO error to have occurred within the calling -** thread. -** -** If the error message is too large for the supplied buffer, -** it should be truncated. The return value of xGetLastError -** is zero if the error message fits in the buffer, or non-zero -** otherwise (if the message was truncated). If non-zero is returned, -** then it is not necessary to include the nul-terminator character -** in the output buffer. -*/ -static int winGetLastError(unqlite_vfs *pVfs, int nBuf, char *zBuf) -{ - /* FormatMessage returns 0 on failure. Otherwise it - ** returns the number of TCHARs written to the output - ** buffer, excluding the terminating null char. - */ - DWORD error = GetLastError(); - WCHAR *zTempWide = 0; - DWORD dwLen; - char *zOut = 0; - - SXUNUSED(pVfs); - dwLen = FormatMessageW( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, - 0, - error, - 0, - (LPWSTR) &zTempWide, - 0, - 0 - ); - if( dwLen > 0 ){ - /* allocate a buffer and convert to UTF8 */ - zOut = unicodeToUtf8(zTempWide); - /* free the system buffer allocated by FormatMessage */ - LocalFree(zTempWide); - } - if( 0 == dwLen ){ - Systrcpy(zBuf,(sxu32)nBuf,"OS Error",sizeof("OS Error")-1); - }else{ - /* copy a maximum of nBuf chars to output buffer */ - Systrcpy(zBuf,(sxu32)nBuf,zOut,0 /* Compute input length automatically */); - /* free the UTF8 buffer */ - HeapFree(GetProcessHeap(),0,zOut); - } - return 0; -} -/* -** Open a file. -*/ -static int winOpen( - unqlite_vfs *pVfs, /* Not used */ - const char *zName, /* Name of the file (UTF-8) */ - unqlite_file *id, /* Write the UnQLite file handle here */ - unsigned int flags /* Open mode flags */ -){ - HANDLE h; - DWORD dwDesiredAccess; - DWORD dwShareMode; - DWORD dwCreationDisposition; - DWORD dwFlagsAndAttributes = 0; - winFile *pFile = (winFile*)id; - void *zConverted; /* Filename in OS encoding */ - const char *zUtf8Name = zName; /* Filename in UTF-8 encoding */ - int isExclusive = (flags & UNQLITE_OPEN_EXCLUSIVE); - int isDelete = (flags & UNQLITE_OPEN_TEMP_DB); - int isCreate = (flags & UNQLITE_OPEN_CREATE); - int isReadWrite = (flags & UNQLITE_OPEN_READWRITE); - - pFile->h = INVALID_HANDLE_VALUE; - /* Convert the filename to the system encoding. */ - zConverted = convertUtf8Filename(zUtf8Name); - if( zConverted==0 ){ - return UNQLITE_NOMEM; - } - if( isReadWrite ){ - dwDesiredAccess = GENERIC_READ | GENERIC_WRITE; - }else{ - dwDesiredAccess = GENERIC_READ; - } - /* UNQLITE_OPEN_EXCLUSIVE is used to make sure that a new file is - ** created. - */ - if( isExclusive ){ - /* Creates a new file, only if it does not already exist. */ - /* If the file exists, it fails. */ - dwCreationDisposition = CREATE_NEW; - }else if( isCreate ){ - /* Open existing file, or create if it doesn't exist */ - dwCreationDisposition = OPEN_ALWAYS; - }else{ - /* Opens a file, only if it exists. */ - dwCreationDisposition = OPEN_EXISTING; - } - - dwShareMode = FILE_SHARE_READ | FILE_SHARE_WRITE; - - if( isDelete ){ - dwFlagsAndAttributes = FILE_ATTRIBUTE_TEMPORARY - | FILE_ATTRIBUTE_HIDDEN - | FILE_FLAG_DELETE_ON_CLOSE; - }else{ - dwFlagsAndAttributes = FILE_ATTRIBUTE_NORMAL; - } - h = CreateFileW((WCHAR*)zConverted, - dwDesiredAccess, - dwShareMode, - NULL, - dwCreationDisposition, - dwFlagsAndAttributes, - NULL - ); - if( h==INVALID_HANDLE_VALUE ){ - pFile->lastErrno = GetLastError(); - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_IOERR; - } - SyZero(pFile,sizeof(*pFile)); - pFile->pMethod = &winIoMethod; - pFile->h = h; - pFile->lastErrno = NO_ERROR; - pFile->pVfs = pVfs; - pFile->sectorSize = getSectorSize(pVfs, zUtf8Name); - HeapFree(GetProcessHeap(),0,zConverted); - return UNQLITE_OK; -} -/* - * Export the Windows Vfs. - */ -UNQLITE_PRIVATE const unqlite_vfs * unqliteExportBuiltinVfs(void) -{ - static const unqlite_vfs sWinvfs = { - "Windows", /* Vfs name */ - 1, /* Vfs structure version */ - sizeof(winFile), /* szOsFile */ - MAX_PATH, /* mxPathName */ - winOpen, /* xOpen */ - winDelete, /* xDelete */ - winAccess, /* xAccess */ - winFullPathname, /* xFullPathname */ - 0, /* xTmp */ - winSleep, /* xSleep */ - winCurrentTime, /* xCurrentTime */ - winGetLastError, /* xGetLastError */ - }; - return &sWinvfs; -} -#endif /* __WINNT__ */ -/* - * ---------------------------------------------------------- - * File: pager.c - * MD5: 57ff77347402fbf6892af589ff8a5df7 - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: pager.c v1.1 Win7 2012-11-29 03:46 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* -** This file implements the pager and the transaction manager for UnQLite (Mostly inspired from the SQLite3 Source tree). -** -** The Pager.eState variable stores the current 'state' of a pager. A -** pager may be in any one of the seven states shown in the following -** state diagram. -** -** OPEN <------+------+ -** | | | -** V | | -** +---------> READER-------+ | -** | | | -** | V | -** |<-------WRITER_LOCKED--------->| -** | | | -** | V | -** |<------WRITER_CACHEMOD-------->| -** | | | -** | V | -** |<-------WRITER_DBMOD---------->| -** | | | -** | V | -** +<------WRITER_FINISHED-------->+ -** -** OPEN: -** -** The pager starts up in this state. Nothing is guaranteed in this -** state - the file may or may not be locked and the database size is -** unknown. The database may not be read or written. -** -** * No read or write transaction is active. -** * Any lock, or no lock at all, may be held on the database file. -** * The dbSize and dbOrigSize variables may not be trusted. -** -** READER: -** -** In this state all the requirements for reading the database in -** rollback mode are met. Unless the pager is (or recently -** was) in exclusive-locking mode, a user-level read transaction is -** open. The database size is known in this state. -** -** * A read transaction may be active (but a write-transaction cannot). -** * A SHARED or greater lock is held on the database file. -** * The dbSize variable may be trusted (even if a user-level read -** transaction is not active). The dbOrigSize variables -** may not be trusted at this point. -** * Even if a read-transaction is not open, it is guaranteed that -** there is no hot-journal in the file-system. -** -** WRITER_LOCKED: -** -** The pager moves to this state from READER when a write-transaction -** is first opened on the database. In WRITER_LOCKED state, all locks -** required to start a write-transaction are held, but no actual -** modifications to the cache or database have taken place. -** -** In rollback mode, a RESERVED or (if the transaction was opened with -** EXCLUSIVE flag) EXCLUSIVE lock is obtained on the database file when -** moving to this state, but the journal file is not written to or opened -** to in this state. If the transaction is committed or rolled back while -** in WRITER_LOCKED state, all that is required is to unlock the database -** file. -** -** * A write transaction is active. -** * If the connection is open in rollback-mode, a RESERVED or greater -** lock is held on the database file. -** * The dbSize and dbOrigSize variables are all valid. -** * The contents of the pager cache have not been modified. -** * The journal file may or may not be open. -** * Nothing (not even the first header) has been written to the journal. -** -** WRITER_CACHEMOD: -** -** A pager moves from WRITER_LOCKED state to this state when a page is -** first modified by the upper layer. In rollback mode the journal file -** is opened (if it is not already open) and a header written to the -** start of it. The database file on disk has not been modified. -** -** * A write transaction is active. -** * A RESERVED or greater lock is held on the database file. -** * The journal file is open and the first header has been written -** to it, but the header has not been synced to disk. -** * The contents of the page cache have been modified. -** -** WRITER_DBMOD: -** -** The pager transitions from WRITER_CACHEMOD into WRITER_DBMOD state -** when it modifies the contents of the database file. -** -** * A write transaction is active. -** * An EXCLUSIVE or greater lock is held on the database file. -** * The journal file is open and the first header has been written -** and synced to disk. -** * The contents of the page cache have been modified (and possibly -** written to disk). -** -** WRITER_FINISHED: -** -** A rollback-mode pager changes to WRITER_FINISHED state from WRITER_DBMOD -** state after the entire transaction has been successfully written into the -** database file. In this state the transaction may be committed simply -** by finalizing the journal file. Once in WRITER_FINISHED state, it is -** not possible to modify the database further. At this point, the upper -** layer must either commit or rollback the transaction. -** -** * A write transaction is active. -** * An EXCLUSIVE or greater lock is held on the database file. -** * All writing and syncing of journal and database data has finished. -** If no error occured, all that remains is to finalize the journal to -** commit the transaction. If an error did occur, the caller will need -** to rollback the transaction. -** -** -*/ -#define PAGER_OPEN 0 -#define PAGER_READER 1 -#define PAGER_WRITER_LOCKED 2 -#define PAGER_WRITER_CACHEMOD 3 -#define PAGER_WRITER_DBMOD 4 -#define PAGER_WRITER_FINISHED 5 -/* -** Journal files begin with the following magic string. The data -** was obtained from /dev/random. It is used only as a sanity check. -** -** NOTE: These values must be different from the one used by SQLite3 -** to avoid journal file collision. -** -*/ -static const unsigned char aJournalMagic[] = { - 0xa6, 0xe8, 0xcd, 0x2b, 0x1c, 0x92, 0xdb, 0x9f, -}; -/* -** The journal header size for this pager. This is usually the same -** size as a single disk sector. See also setSectorSize(). -*/ -#define JOURNAL_HDR_SZ(pPager) (pPager->iSectorSize) -/* - * Database page handle. - * Each raw disk page is represented in memory by an instance - * of the following structure. - */ -typedef struct Page Page; -struct Page { - /* Must correspond to unqlite_page */ - unsigned char *zData; /* Content of this page */ - void *pUserData; /* Extra content */ - pgno pgno; /* Page number for this page */ - /********************************************************************** - ** Elements above are public. All that follows is private to pcache.c - ** and should not be accessed by other modules. - */ - Pager *pPager; /* The pager this page is part of */ - int flags; /* Page flags defined below */ - int nRef; /* Number of users of this page */ - Page *pNext, *pPrev; /* A list of all pages */ - Page *pDirtyNext; /* Next element in list of dirty pages */ - Page *pDirtyPrev; /* Previous element in list of dirty pages */ - Page *pNextCollide,*pPrevCollide; /* Collission chain */ - Page *pNextHot,*pPrevHot; /* Hot dirty pages chain */ -}; -/* Bit values for Page.flags */ -#define PAGE_DIRTY 0x002 /* Page has changed */ -#define PAGE_NEED_SYNC 0x004 /* fsync the rollback journal before - ** writing this page to the database */ -#define PAGE_DONT_WRITE 0x008 /* Dont write page content to disk */ -#define PAGE_NEED_READ 0x010 /* Content is unread */ -#define PAGE_IN_JOURNAL 0x020 /* Page written to the journal */ -#define PAGE_HOT_DIRTY 0x040 /* Hot dirty page */ -#define PAGE_DONT_MAKE_HOT 0x080 /* Dont make this page Hot. In other words, - * do not link it to the hot dirty list. - */ -/* - * Each active database pager is represented by an instance of - * the following structure. - */ -struct Pager -{ - SyMemBackend *pAllocator; /* Memory backend */ - unqlite *pDb; /* DB handle that own this instance */ - unqlite_kv_engine *pEngine; /* Underlying KV storage engine */ - char *zFilename; /* Name of the database file */ - char *zJournal; /* Name of the journal file */ - unqlite_vfs *pVfs; /* Underlying virtual file system */ - unqlite_file *pfd,*pjfd; /* File descriptors for database and journal */ - pgno dbSize; /* Number of pages in the file */ - pgno dbOrigSize; /* dbSize before the current change */ - sxi64 dbByteSize; /* Database size in bytes */ - void *pMmap; /* Read-only Memory view (mmap) of the whole file if requested (UNQLITE_OPEN_MMAP). */ - sxu32 nRec; /* Number of pages written to the journal */ - SyPRNGCtx sPrng; /* PRNG Context */ - sxu32 cksumInit; /* Quasi-random value added to every checksum */ - sxu32 iOpenFlags; /* Flag passed to unqlite_open() after processing */ - sxi64 iJournalOfft; /* Journal offset we are reading from */ - int (*xBusyHandler)(void *); /* Busy handler */ - void *pBusyHandlerArg; /* First arg to xBusyHandler() */ - void (*xPageUnpin)(void *); /* Page Unpin callback */ - void (*xPageReload)(void *); /* Page Reload callback */ - Bitvec *pVec; /* Bitmap */ - Page *pHeader; /* Page one of the database (Unqlite header) */ - Sytm tmCreate; /* Database creation time */ - SyString sKv; /* Underlying Key/Value storage engine name */ - int iState; /* Pager state */ - int iLock; /* Lock state */ - sxi32 iFlags; /* Control flags (see below) */ - int is_mem; /* True for an in-memory database */ - int is_rdonly; /* True for a read-only database */ - int no_jrnl; /* TRUE to omit journaling */ - int iPageSize; /* Page size in bytes (default 4K) */ - int iSectorSize; /* Size of a single sector on disk */ - unsigned char *zTmpPage; /* Temporary page */ - Page *pFirstDirty; /* First dirty pages */ - Page *pDirty; /* Transient list of dirty pages */ - Page *pAll; /* List of all pages */ - Page *pHotDirty; /* List of hot dirty pages */ - Page *pFirstHot; /* First hot dirty page */ - sxu32 nHot; /* Total number of hot dirty pages */ - Page **apHash; /* Page table */ - sxu32 nSize; /* apHash[] size: Must be a power of two */ - sxu32 nPage; /* Total number of page loaded in memory */ - sxu32 nCacheMax; /* Maximum page to cache*/ -}; -/* Control flags */ -#define PAGER_CTRL_COMMIT_ERR 0x001 /* Commit error */ -#define PAGER_CTRL_DIRTY_COMMIT 0x002 /* Dirty commit has been applied */ -/* -** Read a 32-bit integer from the given file descriptor. -** All values are stored on disk as big-endian. -*/ -static int ReadInt32(unqlite_file *pFd,sxu32 *pOut,sxi64 iOfft) -{ - unsigned char zBuf[4]; - int rc; - rc = unqliteOsRead(pFd,zBuf,sizeof(zBuf),iOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - SyBigEndianUnpack32(zBuf,pOut); - return UNQLITE_OK; -} -/* -** Read a 64-bit integer from the given file descriptor. -** All values are stored on disk as big-endian. -*/ -static int ReadInt64(unqlite_file *pFd,sxu64 *pOut,sxi64 iOfft) -{ - unsigned char zBuf[8]; - int rc; - rc = unqliteOsRead(pFd,zBuf,sizeof(zBuf),iOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - SyBigEndianUnpack64(zBuf,pOut); - return UNQLITE_OK; -} -/* -** Write a 32-bit integer into the given file descriptor. -*/ -static int WriteInt32(unqlite_file *pFd,sxu32 iNum,sxi64 iOfft) -{ - unsigned char zBuf[4]; - int rc; - SyBigEndianPack32(zBuf,iNum); - rc = unqliteOsWrite(pFd,zBuf,sizeof(zBuf),iOfft); - return rc; -} -/* -** Write a 64-bit integer into the given file descriptor. -*/ -static int WriteInt64(unqlite_file *pFd,sxu64 iNum,sxi64 iOfft) -{ - unsigned char zBuf[8]; - int rc; - SyBigEndianPack64(zBuf,iNum); - rc = unqliteOsWrite(pFd,zBuf,sizeof(zBuf),iOfft); - return rc; -} -/* -** The maximum allowed sector size. 64KiB. If the xSectorsize() method -** returns a value larger than this, then MAX_SECTOR_SIZE is used instead. -** This could conceivably cause corruption following a power failure on -** such a system. This is currently an undocumented limit. -*/ -#define MAX_SECTOR_SIZE 0x10000 -/* -** Get the size of a single sector on disk. -** The sector size will be used used to determine the size -** and alignment of journal header and within created journal files. -** -** The default sector size is set to 512. -*/ -static int GetSectorSize(unqlite_file *pFd) -{ - int iSectorSize = UNQLITE_DEFAULT_SECTOR_SIZE; - if( pFd ){ - iSectorSize = unqliteOsSectorSize(pFd); - if( iSectorSize < 32 ){ - iSectorSize = 512; - } - if( iSectorSize > MAX_SECTOR_SIZE ){ - iSectorSize = MAX_SECTOR_SIZE; - } - } - return iSectorSize; -} -/* Hash function for page number */ -#define PAGE_HASH(PNUM) (PNUM) -/* - * Fetch a page from the cache. - */ -static Page * pager_fetch_page(Pager *pPager,pgno page_num) -{ - Page *pEntry; - if( pPager->nPage < 1 ){ - /* Don't bother hashing */ - return 0; - } - /* Perform the lookup */ - pEntry = pPager->apHash[PAGE_HASH(page_num) & (pPager->nSize - 1)]; - for(;;){ - if( pEntry == 0 ){ - break; - } - if( pEntry->pgno == page_num ){ - return pEntry; - } - /* Point to the next entry in the colission chain */ - pEntry = pEntry->pNextCollide; - } - /* No such page */ - return 0; -} -/* - * Allocate and initialize a new page. - */ -static Page * pager_alloc_page(Pager *pPager,pgno num_page) -{ - Page *pNew; - - pNew = (Page *)SyMemBackendPoolAlloc(pPager->pAllocator,sizeof(Page)+pPager->iPageSize); - if( pNew == 0 ){ - return 0; - } - /* Zero the structure */ - SyZero(pNew,sizeof(Page)+pPager->iPageSize); - /* Page data */ - pNew->zData = (unsigned char *)&pNew[1]; - /* Fill in the structure */ - pNew->pPager = pPager; - pNew->nRef = 1; - pNew->pgno = num_page; - return pNew; -} -/* - * Increment the reference count of a given page. - */ -static void page_ref(Page *pPage) -{ - if( pPage->pPager->pAllocator->pMutexMethods ){ - SyMutexEnter(pPage->pPager->pAllocator->pMutexMethods, pPage->pPager->pAllocator->pMutex); - } - pPage->nRef++; - if( pPage->pPager->pAllocator->pMutexMethods ){ - SyMutexLeave(pPage->pPager->pAllocator->pMutexMethods, pPage->pPager->pAllocator->pMutex); - } -} -/* - * Release an in-memory page after its reference count reach zero. - */ -static int pager_release_page(Pager *pPager,Page *pPage) -{ - int rc = UNQLITE_OK; - if( !(pPage->flags & PAGE_DIRTY)){ - /* Invoke the unpin callback if available */ - if( pPager->xPageUnpin && pPage->pUserData ){ - pPager->xPageUnpin(pPage->pUserData); - } - pPage->pUserData = 0; - SyMemBackendPoolFree(pPager->pAllocator,pPage); - }else{ - /* Dirty page, it will be released later when a dirty commit - * or the final commit have been applied. - */ - rc = UNQLITE_LOCKED; - } - return rc; -} -/* Forward declaration */ -static int pager_unlink_page(Pager *pPager,Page *pPage); -/* - * Decrement the reference count of a given page. - */ -static void page_unref(Page *pPage) -{ - int nRef; - if( pPage->pPager->pAllocator->pMutexMethods ){ - SyMutexEnter(pPage->pPager->pAllocator->pMutexMethods, pPage->pPager->pAllocator->pMutex); - } - nRef = pPage->nRef--; - if( pPage->pPager->pAllocator->pMutexMethods ){ - SyMutexLeave(pPage->pPager->pAllocator->pMutexMethods, pPage->pPager->pAllocator->pMutex); - } - if( nRef == 0){ - Pager *pPager = pPage->pPager; - if( !(pPage->flags & PAGE_DIRTY) ){ - pager_unlink_page(pPager,pPage); - /* Release the page */ - pager_release_page(pPager,pPage); - }else{ - if( pPage->flags & PAGE_DONT_MAKE_HOT ){ - /* Do not add this page to the hot dirty list */ - return; - } - if( !(pPage->flags & PAGE_HOT_DIRTY) ){ - /* Add to the hot dirty list */ - pPage->pPrevHot = 0; - if( pPager->pFirstHot == 0 ){ - pPager->pFirstHot = pPager->pHotDirty = pPage; - }else{ - pPage->pNextHot = pPager->pHotDirty; - if( pPager->pHotDirty ){ - pPager->pHotDirty->pPrevHot = pPage; - } - pPager->pHotDirty = pPage; - } - pPager->nHot++; - pPage->flags |= PAGE_HOT_DIRTY; - } - } - } -} -/* - * Link a freshly created page to the list of active page. - */ -static int pager_link_page(Pager *pPager,Page *pPage) -{ - sxu32 nBucket; - /* Install in the corresponding bucket */ - nBucket = PAGE_HASH(pPage->pgno) & (pPager->nSize - 1); - pPage->pNextCollide = pPager->apHash[nBucket]; - if( pPager->apHash[nBucket] ){ - pPager->apHash[nBucket]->pPrevCollide = pPage; - } - pPager->apHash[nBucket] = pPage; - /* Link to the list of active pages */ - MACRO_LD_PUSH(pPager->pAll,pPage); - pPager->nPage++; - if( (pPager->nPage >= pPager->nSize * 4) && pPager->nPage < 100000 ){ - /* Grow the hashtable */ - sxu32 nNewSize = pPager->nSize << 1; - Page *pEntry,**apNew; - sxu32 n; - apNew = (Page **)SyMemBackendAlloc(pPager->pAllocator, nNewSize * sizeof(Page *)); - if( apNew ){ - sxu32 iBucket; - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(Page *)); - /* Rehash all entries */ - n = 0; - pEntry = pPager->pAll; - for(;;){ - /* Loop one */ - if( n >= pPager->nPage ){ - break; - } - pEntry->pNextCollide = pEntry->pPrevCollide = 0; - /* Install in the new bucket */ - iBucket = PAGE_HASH(pEntry->pgno) & (nNewSize - 1); - pEntry->pNextCollide = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevCollide = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(pPager->pAllocator,(void *)pPager->apHash); - pPager->apHash = apNew; - pPager->nSize = nNewSize; - } - } - return UNQLITE_OK; -} -/* - * Unlink a page from the list of active pages. - */ -static int pager_unlink_page(Pager *pPager,Page *pPage) -{ - if( pPage->pNextCollide ){ - pPage->pNextCollide->pPrevCollide = pPage->pPrevCollide; - } - if( pPage->pPrevCollide ){ - pPage->pPrevCollide->pNextCollide = pPage->pNextCollide; - }else{ - sxu32 nBucket = PAGE_HASH(pPage->pgno) & (pPager->nSize - 1); - pPager->apHash[nBucket] = pPage->pNextCollide; - } - MACRO_LD_REMOVE(pPager->pAll,pPage); - pPager->nPage--; - return UNQLITE_OK; -} -/* - * Update the content of a cached page. - */ -static int pager_fill_page(Pager *pPager,pgno iNum,void *pContents) -{ - Page *pPage; - /* Fetch the page from the catch */ - pPage = pager_fetch_page(pPager,iNum); - if( pPage == 0 ){ - return SXERR_NOTFOUND; - } - /* Reflect the change */ - SyMemcpy(pContents,pPage->zData,pPager->iPageSize); - - return UNQLITE_OK; -} -/* - * Read the content of a page from disk. - */ -static int pager_get_page_contents(Pager *pPager,Page *pPage,int noContent) -{ - int rc = UNQLITE_OK; - if( pPager->is_mem || noContent || pPage->pgno >= pPager->dbSize ){ - /* Do not bother reading, zero the page contents only */ - SyZero(pPage->zData,pPager->iPageSize); - return UNQLITE_OK; - } - if( (pPager->iOpenFlags & UNQLITE_OPEN_MMAP) && (pPager->pMmap /* Paranoid edition */) ){ - unsigned char *zMap = (unsigned char *)pPager->pMmap; - pPage->zData = &zMap[pPage->pgno * pPager->iPageSize]; - }else{ - /* Read content */ - rc = unqliteOsRead(pPager->pfd,pPage->zData,pPager->iPageSize,pPage->pgno * pPager->iPageSize); - } - return rc; -} -/* - * Add a page to the dirty list. - */ -static void pager_page_to_dirty_list(Pager *pPager,Page *pPage) -{ - if( pPage->flags & PAGE_DIRTY ){ - /* Already set */ - return; - } - /* Mark the page as dirty */ - pPage->flags |= PAGE_DIRTY|PAGE_NEED_SYNC|PAGE_IN_JOURNAL; - /* Link to the list */ - pPage->pDirtyPrev = 0; - pPage->pDirtyNext = pPager->pDirty; - if( pPager->pDirty ){ - pPager->pDirty->pDirtyPrev = pPage; - } - pPager->pDirty = pPage; - if( pPager->pFirstDirty == 0 ){ - pPager->pFirstDirty = pPage; - } -} -/* - * Merge sort. - * The merge sort implementation is based on the one used by - * the PH7 Embeddable PHP Engine (http://ph7.symisc.net/). - */ -/* -** Inputs: -** a: A sorted, null-terminated linked list. (May be null). -** b: A sorted, null-terminated linked list. (May be null). -** cmp: A pointer to the comparison function. -** -** Return Value: -** A pointer to the head of a sorted list containing the elements -** of both a and b. -** -** Side effects: -** The "next", "prev" pointers for elements in the lists a and b are -** changed. -*/ -static Page * page_merge_dirty(Page *pA, Page *pB) -{ - Page result, *pTail; - /* Prevent compiler warning */ - result.pDirtyNext = result.pDirtyPrev = 0; - pTail = &result; - while( pA && pB ){ - if( pA->pgno < pB->pgno ){ - pTail->pDirtyPrev = pA; - pA->pDirtyNext = pTail; - pTail = pA; - pA = pA->pDirtyPrev; - }else{ - pTail->pDirtyPrev = pB; - pB->pDirtyNext = pTail; - pTail = pB; - pB = pB->pDirtyPrev; - } - } - if( pA ){ - pTail->pDirtyPrev = pA; - pA->pDirtyNext = pTail; - }else if( pB ){ - pTail->pDirtyPrev = pB; - pB->pDirtyNext = pTail; - }else{ - pTail->pDirtyPrev = pTail->pDirtyNext = 0; - } - return result.pDirtyPrev; -} -/* -** Inputs: -** Map: Input hashmap -** cmp: A comparison function. -** -** Return Value: -** Sorted hashmap. -** -** Side effects: -** The "next" pointers for elements in list are changed. -*/ -#define N_SORT_BUCKET 32 -static Page * pager_get_dirty_pages(Pager *pPager) -{ - Page *a[N_SORT_BUCKET], *p, *pIn; - sxu32 i; - if( pPager->pFirstDirty == 0 ){ - /* Don't bother sorting, the list is already empty */ - return 0; - } - SyZero(a, sizeof(a)); - /* Point to the first inserted entry */ - pIn = pPager->pFirstDirty; - while( pIn ){ - p = pIn; - pIn = p->pDirtyPrev; - p->pDirtyPrev = 0; - for(i=0; ipDirtyNext = 0; - return p; -} -/* - * See block comment above. - */ -static Page * page_merge_hot(Page *pA, Page *pB) -{ - Page result, *pTail; - /* Prevent compiler warning */ - result.pNextHot = result.pPrevHot = 0; - pTail = &result; - while( pA && pB ){ - if( pA->pgno < pB->pgno ){ - pTail->pPrevHot = pA; - pA->pNextHot = pTail; - pTail = pA; - pA = pA->pPrevHot; - }else{ - pTail->pPrevHot = pB; - pB->pNextHot = pTail; - pTail = pB; - pB = pB->pPrevHot; - } - } - if( pA ){ - pTail->pPrevHot = pA; - pA->pNextHot = pTail; - }else if( pB ){ - pTail->pPrevHot = pB; - pB->pNextHot = pTail; - }else{ - pTail->pPrevHot = pTail->pNextHot = 0; - } - return result.pPrevHot; -} -/* -** Inputs: -** Map: Input hashmap -** cmp: A comparison function. -** -** Return Value: -** Sorted hashmap. -** -** Side effects: -** The "next" pointers for elements in list are changed. -*/ -#define N_SORT_BUCKET 32 -static Page * pager_get_hot_pages(Pager *pPager) -{ - Page *a[N_SORT_BUCKET], *p, *pIn; - sxu32 i; - if( pPager->pFirstHot == 0 ){ - /* Don't bother sorting, the list is already empty */ - return 0; - } - SyZero(a, sizeof(a)); - /* Point to the first inserted entry */ - pIn = pPager->pFirstHot; - while( pIn ){ - p = pIn; - pIn = p->pPrevHot; - p->pPrevHot = 0; - for(i=0; ipNextHot = 0; - return p; -} -/* -** The format for the journal header is as follows: -** - 8 bytes: Magic identifying journal format. -** - 4 bytes: Number of records in journal. -** - 4 bytes: Random number used for page hash. -** - 8 bytes: Initial database page count. -** - 4 bytes: Sector size used by the process that wrote this journal. -** - 4 bytes: Database page size. -** -** Followed by (JOURNAL_HDR_SZ - 28) bytes of unused space. -*/ -/* -** Open the journal file and extract its header information. -** -** If the header is read successfully, *pNRec is set to the number of -** page records following this header and *pDbSize is set to the size of the -** database before the transaction began, in pages. Also, pPager->cksumInit -** is set to the value read from the journal header. UNQLITE_OK is returned -** in this case. -** -** If the journal header file appears to be corrupted, UNQLITE_DONE is -** returned and *pNRec and *PDbSize are undefined. If JOURNAL_HDR_SZ bytes -** cannot be read from the journal file an error code is returned. -*/ -static int pager_read_journal_header( - Pager *pPager, /* Pager object */ - sxu32 *pNRec, /* OUT: Value read from the nRec field */ - pgno *pDbSize /* OUT: Value of original database size field */ -) -{ - sxu32 iPageSize,iSectorSize; - unsigned char zMagic[8]; - sxi64 iHdrOfft; - sxi64 iSize; - int rc; - /* Offset to start reading from */ - iHdrOfft = 0; - /* Get the size of the journal */ - rc = unqliteOsFileSize(pPager->pjfd,&iSize); - if( rc != UNQLITE_OK ){ - return UNQLITE_DONE; - } - /* If the journal file is too small, return UNQLITE_DONE. */ - if( 32 /* Minimum sector size */> iSize ){ - return UNQLITE_DONE; - } - /* Make sure we are dealing with a valid journal */ - rc = unqliteOsRead(pPager->pjfd,zMagic,sizeof(zMagic),iHdrOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - if( SyMemcmp(zMagic,aJournalMagic,sizeof(zMagic)) != 0 ){ - return UNQLITE_DONE; - } - iHdrOfft += sizeof(zMagic); - /* Read the first three 32-bit fields of the journal header: The nRec - ** field, the checksum-initializer and the database size at the start - ** of the transaction. Return an error code if anything goes wrong. - */ - rc = ReadInt32(pPager->pjfd,pNRec,iHdrOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - iHdrOfft += 4; - rc = ReadInt32(pPager->pjfd,&pPager->cksumInit,iHdrOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - iHdrOfft += 4; - rc = ReadInt64(pPager->pjfd,pDbSize,iHdrOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - iHdrOfft += 8; - /* Read the page-size and sector-size journal header fields. */ - rc = ReadInt32(pPager->pjfd,&iSectorSize,iHdrOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - iHdrOfft += 4; - rc = ReadInt32(pPager->pjfd,&iPageSize,iHdrOfft); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Check that the values read from the page-size and sector-size fields - ** are within range. To be 'in range', both values need to be a power - ** of two greater than or equal to 512 or 32, and not greater than their - ** respective compile time maximum limits. - */ - if( iPageSize < UNQLITE_MIN_PAGE_SIZE || iSectorSize<32 - || iPageSize > UNQLITE_MAX_PAGE_SIZE || iSectorSize>MAX_SECTOR_SIZE - || ((iPageSize-1)&iPageSize)!=0 || ((iSectorSize-1)&iSectorSize)!=0 - ){ - /* If the either the page-size or sector-size in the journal-header is - ** invalid, then the process that wrote the journal-header must have - ** crashed before the header was synced. In this case stop reading - ** the journal file here. - */ - return UNQLITE_DONE; - } - /* Update the assumed sector-size to match the value used by - ** the process that created this journal. If this journal was - ** created by a process other than this one, then this routine - ** is being called from within pager_playback(). The local value - ** of Pager.sectorSize is restored at the end of that routine. - */ - pPager->iSectorSize = iSectorSize; - pPager->iPageSize = iPageSize; - /* Ready to rollback */ - pPager->iJournalOfft = JOURNAL_HDR_SZ(pPager); - /* All done */ - return UNQLITE_OK; -} -/* - * Write the journal header in the given memory buffer. - * The given buffer is big enough to hold the whole header. - */ -static int pager_write_journal_header(Pager *pPager,unsigned char *zBuf) -{ - unsigned char *zPtr = zBuf; - /* 8 bytes magic number */ - SyMemcpy(aJournalMagic,zPtr,sizeof(aJournalMagic)); - zPtr += sizeof(aJournalMagic); - /* 4 bytes: Number of records in journal. */ - SyBigEndianPack32(zPtr,0); - zPtr += 4; - /* 4 bytes: Random number used to compute page checksum. */ - SyBigEndianPack32(zPtr,pPager->cksumInit); - zPtr += 4; - /* 8 bytes: Initial database page count. */ - SyBigEndianPack64(zPtr,pPager->dbOrigSize); - zPtr += 8; - /* 4 bytes: Sector size used by the process that wrote this journal. */ - SyBigEndianPack32(zPtr,(sxu32)pPager->iSectorSize); - zPtr += 4; - /* 4 bytes: Database page size. */ - SyBigEndianPack32(zPtr,(sxu32)pPager->iPageSize); - return UNQLITE_OK; -} -/* -** Parameter aData must point to a buffer of pPager->pageSize bytes -** of data. Compute and return a checksum based ont the contents of the -** page of data and the current value of pPager->cksumInit. -** -** This is not a real checksum. It is really just the sum of the -** random initial value (pPager->cksumInit) and every 200th byte -** of the page data, starting with byte offset (pPager->pageSize%200). -** Each byte is interpreted as an 8-bit unsigned integer. -** -** Changing the formula used to compute this checksum results in an -** incompatible journal file format. -** -** If journal corruption occurs due to a power failure, the most likely -** scenario is that one end or the other of the record will be changed. -** It is much less likely that the two ends of the journal record will be -** correct and the middle be corrupt. Thus, this "checksum" scheme, -** though fast and simple, catches the mostly likely kind of corruption. -*/ -static sxu32 pager_cksum(Pager *pPager,const unsigned char *zData) -{ - sxu32 cksum = pPager->cksumInit; /* Checksum value to return */ - int i = pPager->iPageSize-200; /* Loop counter */ - while( i>0 ){ - cksum += zData[i]; - i -= 200; - } - return cksum; -} -/* -** Read a single page from the journal file opened on file descriptor -** jfd. Playback this one page. Update the offset to read from. -*/ -static int pager_play_back_one_page(Pager *pPager,sxi64 *pOfft,unsigned char *zTmp) -{ - unsigned char *zData = zTmp; - sxi64 iOfft; /* Offset to read from */ - pgno iNum; /* Pager number */ - sxu32 ckSum; /* Sanity check */ - int rc; - /* Offset to start reading from */ - iOfft = *pOfft; - /* Database page number */ - rc = ReadInt64(pPager->pjfd,&iNum,iOfft); - if( rc != UNQLITE_OK ){ return rc; } - iOfft += 8; - /* Page data */ - rc = unqliteOsRead(pPager->pjfd,zData,pPager->iPageSize,iOfft); - if( rc != UNQLITE_OK ){ return rc; } - iOfft += pPager->iPageSize; - /* Page cksum */ - rc = ReadInt32(pPager->pjfd,&ckSum,iOfft); - if( rc != UNQLITE_OK ){ return rc; } - iOfft += 4; - /* Synchronize pointers */ - *pOfft = iOfft; - /* Make sure we are dealing with a valid page */ - if( ckSum != pager_cksum(pPager,zData) ){ - /* Ignore that page */ - return SXERR_IGNORE; - } - if( iNum >= pPager->dbSize ){ - /* Ignore that page */ - return UNQLITE_OK; - } - /* playback */ - rc = unqliteOsWrite(pPager->pfd,zData,pPager->iPageSize,iNum * pPager->iPageSize); - if( rc == UNQLITE_OK ){ - /* Flush the cache */ - pager_fill_page(pPager,iNum,zData); - } - return rc; -} -/* -** Playback the journal and thus restore the database file to -** the state it was in before we started making changes. -** -** The journal file format is as follows: -** -** (1) 8 byte prefix. A copy of aJournalMagic[]. -** (2) 4 byte big-endian integer which is the number of valid page records -** in the journal. -** (3) 4 byte big-endian integer which is the initial value for the -** sanity checksum. -** (4) 8 byte integer which is the number of pages to truncate the -** database to during a rollback. -** (5) 4 byte big-endian integer which is the sector size. The header -** is this many bytes in size. -** (6) 4 byte big-endian integer which is the page size. -** (7) zero padding out to the next sector size. -** (8) Zero or more pages instances, each as follows: -** + 4 byte page number. -** + pPager->pageSize bytes of data. -** + 4 byte checksum -** -** When we speak of the journal header, we mean the first 7 items above. -** Each entry in the journal is an instance of the 8th item. -** -** Call the value from the second bullet "nRec". nRec is the number of -** valid page entries in the journal. In most cases, you can compute the -** value of nRec from the size of the journal file. But if a power -** failure occurred while the journal was being written, it could be the -** case that the size of the journal file had already been increased but -** the extra entries had not yet made it safely to disk. In such a case, -** the value of nRec computed from the file size would be too large. For -** that reason, we always use the nRec value in the header. -** -** If the file opened as the journal file is not a well-formed -** journal file then all pages up to the first corrupted page are rolled -** back (or no pages if the journal header is corrupted). The journal file -** is then deleted and SQLITE_OK returned, just as if no corruption had -** been encountered. -** -** If an I/O or malloc() error occurs, the journal-file is not deleted -** and an error code is returned. -** -*/ -static int pager_playback(Pager *pPager) -{ - unsigned char *zTmp = 0; /* cc warning */ - sxu32 n,nRec; - sxi64 iOfft; - int rc; - /* Read the journal header*/ - rc = pager_read_journal_header(pPager,&nRec,&pPager->dbSize); - if( rc != UNQLITE_OK ){ - if( rc == UNQLITE_DONE ){ - goto end_playback; - } - unqliteGenErrorFormat(pPager->pDb,"IO error while reading journal file '%s' header",pPager->zJournal); - return rc; - } - /* Truncate the database back to its original size */ - rc = unqliteOsTruncate(pPager->pfd,pPager->iPageSize * pPager->dbSize); - if( rc != UNQLITE_OK ){ - unqliteGenError(pPager->pDb,"IO error while truncating database file"); - return rc; - } - /* Allocate a temporary page */ - zTmp = (unsigned char *)SyMemBackendAlloc(pPager->pAllocator,(sxu32)pPager->iPageSize); - if( zTmp == 0 ){ - unqliteGenOutofMem(pPager->pDb); - return UNQLITE_NOMEM; - } - SyZero((void *)zTmp,(sxu32)pPager->iPageSize); - /* Copy original pages out of the journal and back into the - ** database file and/or page cache. - */ - iOfft = pPager->iJournalOfft; - for( n = 0 ; n < nRec ; ++n ){ - rc = pager_play_back_one_page(pPager,&iOfft,zTmp); - if( rc != UNQLITE_OK ){ - if( rc != SXERR_IGNORE ){ - unqliteGenError(pPager->pDb,"Page playback error"); - goto end_playback; - } - } - } -end_playback: - /* Release the temp page */ - SyMemBackendFree(pPager->pAllocator,(void *)zTmp); - if( rc == UNQLITE_OK ){ - /* Sync the database file */ - unqliteOsSync(pPager->pfd,UNQLITE_SYNC_FULL); - } - if( rc == UNQLITE_DONE ){ - rc = UNQLITE_OK; - } - /* Return to the caller */ - return rc; -} -/* -** Unlock the database file to level eLock, which must be either NO_LOCK -** or SHARED_LOCK. Regardless of whether or not the call to xUnlock() -** succeeds, set the Pager.iLock variable to match the (attempted) new lock. -** -** Except, if Pager.iLock is set to NO_LOCK when this function is -** called, do not modify it. See the comment above the #define of -** NO_LOCK for an explanation of this. -*/ -static int pager_unlock_db(Pager *pPager, int eLock) -{ - int rc = UNQLITE_OK; - if( pPager->iLock != NO_LOCK ){ - rc = unqliteOsUnlock(pPager->pfd,eLock); - pPager->iLock = eLock; - } - return rc; -} -/* -** Lock the database file to level eLock, which must be either SHARED_LOCK, -** RESERVED_LOCK or EXCLUSIVE_LOCK. If the caller is successful, set the -** Pager.eLock variable to the new locking state. -** -** Except, if Pager.eLock is set to NO_LOCK when this function is -** called, do not modify it unless the new locking state is EXCLUSIVE_LOCK. -** See the comment above the #define of NO_LOCK for an explanation -** of this. -*/ -static int pager_lock_db(Pager *pPager, int eLock){ - int rc = UNQLITE_OK; - if( pPager->iLock < eLock || pPager->iLock == NO_LOCK ){ - rc = unqliteOsLock(pPager->pfd, eLock); - if( rc==UNQLITE_OK ){ - pPager->iLock = eLock; - }else{ - unqliteGenError(pPager->pDb, - rc == UNQLITE_BUSY ? "Another process or thread hold the requested lock" : "Error while requesting database lock" - ); - } - } - return rc; -} -/* -** Try to obtain a lock of type locktype on the database file. If -** a similar or greater lock is already held, this function is a no-op -** (returning UNQLITE_OK immediately). -** -** Otherwise, attempt to obtain the lock using unqliteOsLock(). Invoke -** the busy callback if the lock is currently not available. Repeat -** until the busy callback returns false or until the attempt to -** obtain the lock succeeds. -** -** Return UNQLITE_OK on success and an error code if we cannot obtain -** the lock. If the lock is obtained successfully, set the Pager.state -** variable to locktype before returning. -*/ -static int pager_wait_on_lock(Pager *pPager, int locktype){ - int rc; /* Return code */ - do { - rc = pager_lock_db(pPager,locktype); - }while( rc==UNQLITE_BUSY && pPager->xBusyHandler && pPager->xBusyHandler(pPager->pBusyHandlerArg) ); - return rc; -} -/* -** This function is called after transitioning from PAGER_OPEN to -** PAGER_SHARED state. It tests if there is a hot journal present in -** the file-system for the given pager. A hot journal is one that -** needs to be played back. According to this function, a hot-journal -** file exists if the following criteria are met: -** -** * The journal file exists in the file system, and -** * No process holds a RESERVED or greater lock on the database file, and -** * The database file itself is greater than 0 bytes in size, and -** * The first byte of the journal file exists and is not 0x00. -** -** If the current size of the database file is 0 but a journal file -** exists, that is probably an old journal left over from a prior -** database with the same name. In this case the journal file is -** just deleted using OsDelete, *pExists is set to 0 and UNQLITE_OK -** is returned. -** -** If a hot-journal file is found to exist, *pExists is set to 1 and -** UNQLITE_OK returned. If no hot-journal file is present, *pExists is -** set to 0 and UNQLITE_OK returned. If an IO error occurs while trying -** to determine whether or not a hot-journal file exists, the IO error -** code is returned and the value of *pExists is undefined. -*/ -static int pager_has_hot_journal(Pager *pPager, int *pExists) -{ - unqlite_vfs *pVfs = pPager->pVfs; - int rc = UNQLITE_OK; /* Return code */ - int exists = 1; /* True if a journal file is present */ - - *pExists = 0; - rc = unqliteOsAccess(pVfs, pPager->zJournal, UNQLITE_ACCESS_EXISTS, &exists); - if( rc==UNQLITE_OK && exists ){ - int locked = 0; /* True if some process holds a RESERVED lock */ - - /* Race condition here: Another process might have been holding the - ** the RESERVED lock and have a journal open at the unqliteOsAccess() - ** call above, but then delete the journal and drop the lock before - ** we get to the following unqliteOsCheckReservedLock() call. If that - ** is the case, this routine might think there is a hot journal when - ** in fact there is none. This results in a false-positive which will - ** be dealt with by the playback routine. - */ - rc = unqliteOsCheckReservedLock(pPager->pfd, &locked); - if( rc==UNQLITE_OK && !locked ){ - sxi64 n = 0; /* Size of db file in bytes */ - - /* Check the size of the database file. If it consists of 0 pages, - ** then delete the journal file. See the header comment above for - ** the reasoning here. Delete the obsolete journal file under - ** a RESERVED lock to avoid race conditions. - */ - rc = unqliteOsFileSize(pPager->pfd,&n); - if( rc==UNQLITE_OK ){ - if( n < 1 ){ - if( pager_lock_db(pPager, RESERVED_LOCK)==UNQLITE_OK ){ - unqliteOsDelete(pVfs, pPager->zJournal, 0); - pager_unlock_db(pPager, SHARED_LOCK); - } - }else{ - /* The journal file exists and no other connection has a reserved - ** or greater lock on the database file. */ - *pExists = 1; - } - } - } - } - return rc; -} -/* - * Rollback a journal file. (See block-comment above). - */ -static int pager_journal_rollback(Pager *pPager,int check_hot) -{ - int rc; - if( check_hot ){ - int iExists = 0; /* cc warning */ - /* Check if the journal file exists */ - rc = pager_has_hot_journal(pPager,&iExists); - if( rc != UNQLITE_OK ){ - /* IO error */ - return rc; - } - if( !iExists ){ - /* Journal file does not exists */ - return UNQLITE_OK; - } - } - if( pPager->is_rdonly ){ - unqliteGenErrorFormat(pPager->pDb, - "Cannot rollback journal file '%s' due to a read-only database handle",pPager->zJournal); - return UNQLITE_READ_ONLY; - } - /* Get an EXCLUSIVE lock on the database file. At this point it is - ** important that a RESERVED lock is not obtained on the way to the - ** EXCLUSIVE lock. If it were, another process might open the - ** database file, detect the RESERVED lock, and conclude that the - ** database is safe to read while this process is still rolling the - ** hot-journal back. - ** - ** Because the intermediate RESERVED lock is not requested, any - ** other process attempting to access the database file will get to - ** this point in the code and fail to obtain its own EXCLUSIVE lock - ** on the database file. - ** - ** Unless the pager is in locking_mode=exclusive mode, the lock is - ** downgraded to SHARED_LOCK before this function returns. - */ - /* Open the journal file */ - rc = unqliteOsOpen(pPager->pVfs,pPager->pAllocator,pPager->zJournal,&pPager->pjfd,UNQLITE_OPEN_READWRITE); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pPager->pDb,"IO error while opening journal file: '%s'",pPager->zJournal); - goto fail; - } - rc = pager_lock_db(pPager,EXCLUSIVE_LOCK); - if( rc != UNQLITE_OK ){ - unqliteGenError(pPager->pDb,"Cannot acquire an exclusive lock on the database while journal rollback"); - goto fail; - } - /* Sync the journal file */ - unqliteOsSync(pPager->pjfd,UNQLITE_SYNC_NORMAL); - /* Finally rollback the database */ - rc = pager_playback(pPager); - /* Switch back to shared lock */ - pager_unlock_db(pPager,SHARED_LOCK); -fail: - /* Close the journal handle */ - unqliteOsCloseFree(pPager->pAllocator,pPager->pjfd); - pPager->pjfd = 0; - if( rc == UNQLITE_OK ){ - /* Delete the journal file */ - unqliteOsDelete(pPager->pVfs,pPager->zJournal,TRUE); - } - return rc; -} -/* - * Write the unqlite header (First page). (Big-Endian) - */ -static int pager_write_db_header(Pager *pPager) -{ - unsigned char *zRaw = pPager->pHeader->zData; - unqlite_kv_engine *pEngine = pPager->pEngine; - sxu32 nDos; - sxu16 nLen; - /* Database signature */ - SyMemcpy(UNQLITE_DB_SIG,zRaw,sizeof(UNQLITE_DB_SIG)-1); - zRaw += sizeof(UNQLITE_DB_SIG)-1; - /* Database magic number */ - SyBigEndianPack32(zRaw,UNQLITE_DB_MAGIC); - zRaw += 4; /* 4 byte magic number */ - /* Database creation time */ - SyZero(&pPager->tmCreate,sizeof(Sytm)); - if( pPager->pVfs->xCurrentTime ){ - pPager->pVfs->xCurrentTime(pPager->pVfs,&pPager->tmCreate); - } - /* DOS time format (4 bytes) */ - SyTimeFormatToDos(&pPager->tmCreate,&nDos); - SyBigEndianPack32(zRaw,nDos); - zRaw += 4; /* 4 byte DOS time */ - /* Sector size */ - SyBigEndianPack32(zRaw,(sxu32)pPager->iSectorSize); - zRaw += 4; /* 4 byte sector size */ - /* Page size */ - SyBigEndianPack32(zRaw,(sxu32)pPager->iPageSize); - zRaw += 4; /* 4 byte page size */ - /* Key value storage engine */ - nLen = (sxu16)SyStrlen(pEngine->pIo->pMethods->zName); - SyBigEndianPack16(zRaw,nLen); /* 2 byte storage engine name */ - zRaw += 2; - SyMemcpy((const void *)pEngine->pIo->pMethods->zName,(void *)zRaw,nLen); - zRaw += nLen; - /* All rest are meta-data available to the host application */ - return UNQLITE_OK; -} -/* - * Read the unqlite header (first page). (Big-Endian) - */ -static int pager_extract_header(Pager *pPager,const unsigned char *zRaw,sxu32 nByte) -{ - const unsigned char *zEnd = &zRaw[nByte]; - sxu32 nDos,iMagic; - sxu16 nLen; - char *zKv; - /* Database signature */ - if( SyMemcmp(UNQLITE_DB_SIG,zRaw,sizeof(UNQLITE_DB_SIG)-1) != 0 ){ - /* Corrupt database */ - return UNQLITE_CORRUPT; - } - zRaw += sizeof(UNQLITE_DB_SIG)-1; - /* Database magic number */ - SyBigEndianUnpack32(zRaw,&iMagic); - zRaw += 4; /* 4 byte magic number */ - if( iMagic != UNQLITE_DB_MAGIC ){ - /* Corrupt database */ - return UNQLITE_CORRUPT; - } - /* Database creation time */ - SyBigEndianUnpack32(zRaw,&nDos); - zRaw += 4; /* 4 byte DOS time format */ - SyDosTimeFormat(nDos,&pPager->tmCreate); - /* Sector size */ - SyBigEndianUnpack32(zRaw,(sxu32 *)&pPager->iSectorSize); - zRaw += 4; /* 4 byte sector size */ - /* Page size */ - SyBigEndianUnpack32(zRaw,(sxu32 *)&pPager->iPageSize); - zRaw += 4; /* 4 byte page size */ - /* Check that the values read from the page-size and sector-size fields - ** are within range. To be 'in range', both values need to be a power - ** of two greater than or equal to 512 or 32, and not greater than their - ** respective compile time maximum limits. - */ - if( pPager->iPageSizeiSectorSize<32 - || pPager->iPageSize>UNQLITE_MAX_PAGE_SIZE || pPager->iSectorSize>MAX_SECTOR_SIZE - || ((pPager->iPageSize<-1)&pPager->iPageSize)!=0 || ((pPager->iSectorSize-1)&pPager->iSectorSize)!=0 - ){ - return UNQLITE_CORRUPT; - } - /* Key value storage engine */ - SyBigEndianUnpack16(zRaw,&nLen); /* 2 byte storage engine length */ - zRaw += 2; - if( nLen > (sxu16)(zEnd - zRaw) ){ - nLen = (sxu16)(zEnd - zRaw); - } - zKv = (char *)SyMemBackendDup(pPager->pAllocator,(const char *)zRaw,nLen); - if( zKv == 0 ){ - return UNQLITE_NOMEM; - } - SyStringInitFromBuf(&pPager->sKv,zKv,nLen); - return UNQLITE_OK; -} -/* - * Read the database header. - */ -static int pager_read_db_header(Pager *pPager) -{ - unsigned char zRaw[UNQLITE_MIN_PAGE_SIZE]; /* Minimum page size */ - sxi64 n = 0; /* Size of db file in bytes */ - int rc; - /* Get the file size first */ - rc = unqliteOsFileSize(pPager->pfd,&n); - if( rc != UNQLITE_OK ){ - return rc; - } - pPager->dbByteSize = n; - if( n > 0 ){ - unqlite_kv_methods *pMethods; - SyString *pKv; - pgno nPage; - if( n < UNQLITE_MIN_PAGE_SIZE ){ - /* A valid unqlite database must be at least 512 bytes long */ - unqliteGenError(pPager->pDb,"Malformed database image"); - return UNQLITE_CORRUPT; - } - /* Read the database header */ - rc = unqliteOsRead(pPager->pfd,zRaw,sizeof(zRaw),0); - if( rc != UNQLITE_OK ){ - unqliteGenError(pPager->pDb,"IO error while reading database header"); - return rc; - } - /* Extract the header */ - rc = pager_extract_header(pPager,zRaw,sizeof(zRaw)); - if( rc != UNQLITE_OK ){ - unqliteGenError(pPager->pDb,rc == UNQLITE_NOMEM ? "Unqlite is running out of memory" : "Malformed database image"); - return rc; - } - /* Update pager state */ - nPage = (pgno)(n / pPager->iPageSize); - if( nPage==0 && n>0 ){ - nPage = 1; - } - pPager->dbSize = nPage; - /* Laod the target Key/Value storage engine */ - pKv = &pPager->sKv; - pMethods = unqliteFindKVStore(pKv->zString,pKv->nByte); - if( pMethods == 0 ){ - unqliteGenErrorFormat(pPager->pDb,"No such Key/Value storage engine '%z'",pKv); - return UNQLITE_NOTIMPLEMENTED; - } - /* Install the new KV storage engine */ - rc = unqlitePagerRegisterKvEngine(pPager,pMethods); - if( rc != UNQLITE_OK ){ - return rc; - } - }else{ - /* Set a default page and sector size */ - pPager->iSectorSize = GetSectorSize(pPager->pfd); - pPager->iPageSize = unqliteGetPageSize(); - SyStringInitFromBuf(&pPager->sKv,pPager->pEngine->pIo->pMethods->zName,SyStrlen(pPager->pEngine->pIo->pMethods->zName)); - pPager->dbSize = 0; - } - /* Allocate a temporary page size */ - pPager->zTmpPage = (unsigned char *)SyMemBackendAlloc(pPager->pAllocator,(sxu32)pPager->iPageSize); - if( pPager->zTmpPage == 0 ){ - unqliteGenOutofMem(pPager->pDb); - return UNQLITE_NOMEM; - } - SyZero(pPager->zTmpPage,(sxu32)pPager->iPageSize); - return UNQLITE_OK; -} -/* - * Write the database header. - */ -static int pager_create_header(Pager *pPager) -{ - Page *pHeader; - int rc; - /* Allocate a new page */ - pHeader = pager_alloc_page(pPager,0); - if( pHeader == 0 ){ - return UNQLITE_NOMEM; - } - pPager->pHeader = pHeader; - /* Link the page */ - pager_link_page(pPager,pHeader); - /* Add to the dirty list */ - pager_page_to_dirty_list(pPager,pHeader); - /* Write the database header */ - rc = pager_write_db_header(pPager); - return rc; -} -/* -** This function is called to obtain a shared lock on the database file. -** It is illegal to call unqlitePagerAcquire() until after this function -** has been successfully called. If a shared-lock is already held when -** this function is called, it is a no-op. -** -** The following operations are also performed by this function. -** -** 1) If the pager is currently in PAGER_OPEN state (no lock held -** on the database file), then an attempt is made to obtain a -** SHARED lock on the database file. Immediately after obtaining -** the SHARED lock, the file-system is checked for a hot-journal, -** which is played back if present. -** -** If everything is successful, UNQLITE_OK is returned. If an IO error -** occurs while locking the database, checking for a hot-journal file or -** rolling back a journal file, the IO error code is returned. -*/ -static int pager_shared_lock(Pager *pPager) -{ - int rc = UNQLITE_OK; - if( pPager->iState == PAGER_OPEN ){ - unqlite_kv_methods *pMethods; - /* Open the target database */ - rc = unqliteOsOpen(pPager->pVfs,pPager->pAllocator,pPager->zFilename,&pPager->pfd,pPager->iOpenFlags); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pPager->pDb, - "IO error while opening the target database file: %s",pPager->zFilename - ); - return rc; - } - /* Try to obtain a shared lock */ - rc = pager_wait_on_lock(pPager,SHARED_LOCK); - if( rc == UNQLITE_OK ){ - if( pPager->iLock <= SHARED_LOCK ){ - /* Rollback any hot journal */ - rc = pager_journal_rollback(pPager,1); - if( rc != UNQLITE_OK ){ - return rc; - } - } - /* Read the database header */ - rc = pager_read_db_header(pPager); - if( rc != UNQLITE_OK ){ - return rc; - } - if(pPager->dbSize > 0 ){ - if( pPager->iOpenFlags & UNQLITE_OPEN_MMAP ){ - const jx9_vfs *pVfs = jx9ExportBuiltinVfs(); - /* Obtain a read-only memory view of the whole file */ - if( pVfs && pVfs->xMmap ){ - int vr; - vr = pVfs->xMmap(pPager->zFilename,&pPager->pMmap,&pPager->dbByteSize); - if( vr != JX9_OK ){ - /* Generate a warning */ - unqliteGenError(pPager->pDb,"Cannot obtain a read-only memory view of the target database"); - pPager->iOpenFlags &= ~UNQLITE_OPEN_MMAP; - } - }else{ - /* Generate a warning */ - unqliteGenError(pPager->pDb,"Cannot obtain a read-only memory view of the target database"); - pPager->iOpenFlags &= ~UNQLITE_OPEN_MMAP; - } - } - } - /* Update the pager state */ - pPager->iState = PAGER_READER; - /* Invoke the xOpen methods if available */ - pMethods = pPager->pEngine->pIo->pMethods; - if( pMethods->xOpen ){ - rc = pMethods->xOpen(pPager->pEngine,pPager->dbSize); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pPager->pDb, - "xOpen() method of the underlying KV engine '%z' failed", - &pPager->sKv - ); - pager_unlock_db(pPager,NO_LOCK); - pPager->iState = PAGER_OPEN; - return rc; - } - } - }else if( rc == UNQLITE_BUSY ){ - unqliteGenError(pPager->pDb,"Another process or thread have a reserved or exclusive lock on this database"); - } - } - return rc; -} -/* -** Begin a write-transaction on the specified pager object. If a -** write-transaction has already been opened, this function is a no-op. -*/ -UNQLITE_PRIVATE int unqlitePagerBegin(Pager *pPager) -{ - int rc; - /* Obtain a shared lock on the database first */ - rc = pager_shared_lock(pPager); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pPager->iState >= PAGER_WRITER_LOCKED ){ - return UNQLITE_OK; - } - if( pPager->is_rdonly ){ - unqliteGenError(pPager->pDb,"Read-only database"); - /* Read only database */ - return UNQLITE_READ_ONLY; - } - /* Obtain a reserved lock on the database */ - rc = pager_wait_on_lock(pPager,RESERVED_LOCK); - if( rc == UNQLITE_OK ){ - /* Create the bitvec */ - pPager->pVec = unqliteBitvecCreate(pPager->pAllocator,pPager->dbSize); - if( pPager->pVec == 0 ){ - unqliteGenOutofMem(pPager->pDb); - rc = UNQLITE_NOMEM; - goto fail; - } - /* Change to the WRITER_LOCK state */ - pPager->iState = PAGER_WRITER_LOCKED; - pPager->dbOrigSize = pPager->dbSize; - pPager->iJournalOfft = 0; - pPager->nRec = 0; - if( pPager->dbSize < 1 ){ - /* Write the database header */ - rc = pager_create_header(pPager); - if( rc != UNQLITE_OK ){ - goto fail; - } - pPager->dbSize = 1; - } - }else if( rc == UNQLITE_BUSY ){ - unqliteGenError(pPager->pDb,"Another process or thread have a reserved lock on this database"); - } - return rc; -fail: - /* Downgrade to shared lock */ - pager_unlock_db(pPager,SHARED_LOCK); - return rc; -} -/* -** This function is called at the start of every write transaction. -** There must already be a RESERVED or EXCLUSIVE lock on the database -** file when this routine is called. -** -*/ -static int unqliteOpenJournal(Pager *pPager) -{ - unsigned char *zHeader; - int rc = UNQLITE_OK; - if( pPager->is_mem || pPager->no_jrnl ){ - /* Journaling is omitted for this database */ - goto finish; - } - if( pPager->iState >= PAGER_WRITER_CACHEMOD ){ - /* Already opened */ - return UNQLITE_OK; - } - /* Delete any previously journal with the same name */ - unqliteOsDelete(pPager->pVfs,pPager->zJournal,1); - /* Open the journal file */ - rc = unqliteOsOpen(pPager->pVfs,pPager->pAllocator,pPager->zJournal, - &pPager->pjfd,UNQLITE_OPEN_CREATE|UNQLITE_OPEN_READWRITE); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pPager->pDb,"IO error while opening journal file: %s",pPager->zJournal); - return rc; - } - /* Write the journal header */ - zHeader = (unsigned char *)SyMemBackendAlloc(pPager->pAllocator,(sxu32)pPager->iSectorSize); - if( zHeader == 0 ){ - rc = UNQLITE_NOMEM; - goto fail; - } - pager_write_journal_header(pPager,zHeader); - /* Perform the disk write */ - rc = unqliteOsWrite(pPager->pjfd,zHeader,pPager->iSectorSize,0); - /* Offset to start writing from */ - pPager->iJournalOfft = pPager->iSectorSize; - /* All done, journal will be synced later */ - SyMemBackendFree(pPager->pAllocator,zHeader); -finish: - if( rc == UNQLITE_OK ){ - pPager->iState = PAGER_WRITER_CACHEMOD; - return UNQLITE_OK; - } -fail: - /* Unlink the journal file if something goes wrong */ - unqliteOsCloseFree(pPager->pAllocator,pPager->pjfd); - unqliteOsDelete(pPager->pVfs,pPager->zJournal,0); - pPager->pjfd = 0; - return rc; -} -/* -** Sync the journal. In other words, make sure all the pages that have -** been written to the journal have actually reached the surface of the -** disk and can be restored in the event of a hot-journal rollback. -* -* This routine try also to obtain an exlusive lock on the database. -*/ -static int unqliteFinalizeJournal(Pager *pPager,int *pRetry,int close_jrnl) -{ - int rc; - *pRetry = 0; - /* Grab the exclusive lock first */ - rc = pager_lock_db(pPager,EXCLUSIVE_LOCK); - if( rc != UNQLITE_OK ){ - /* Retry the excusive lock process */ - *pRetry = 1; - rc = UNQLITE_OK; - } - if( pPager->no_jrnl ){ - /* Journaling is omitted, return immediately */ - return UNQLITE_OK; - } - /* Write the total number of database records */ - rc = WriteInt32(pPager->pjfd,pPager->nRec,8 /* sizeof(aJournalRec) */); - if( rc != UNQLITE_OK ){ - if( pPager->nRec > 0 ){ - return rc; - }else{ - /* Not so fatal */ - rc = UNQLITE_OK; - } - } - /* Sync the journal and close it */ - rc = unqliteOsSync(pPager->pjfd,UNQLITE_SYNC_NORMAL); - if( close_jrnl ){ - /* close the journal file */ - if( UNQLITE_OK != unqliteOsCloseFree(pPager->pAllocator,pPager->pjfd) ){ - if( rc != UNQLITE_OK /* unqliteOsSync */ ){ - return rc; - } - } - pPager->pjfd = 0; - } - if( (*pRetry) == 1 ){ - if( pager_lock_db(pPager,EXCLUSIVE_LOCK) == UNQLITE_OK ){ - /* Got exclusive lock */ - *pRetry = 0; - } - } - return UNQLITE_OK; -} -/* - * Mark a single data page as writeable. The page is written into the - * main journal as required. - */ -static int page_write(Pager *pPager,Page *pPage) -{ - int rc; - if( !pPager->is_mem && !pPager->no_jrnl ){ - /* Write the page to the transaction journal */ - if( pPage->pgno < pPager->dbOrigSize && !unqliteBitvecTest(pPager->pVec,pPage->pgno) ){ - sxu32 cksum; - if( pPager->nRec == SXU32_HIGH ){ - /* Journal Limit reached */ - unqliteGenError(pPager->pDb,"Journal record limit reached, commit your changes"); - return UNQLITE_LIMIT; - } - /* Write the page number */ - rc = WriteInt64(pPager->pjfd,pPage->pgno,pPager->iJournalOfft); - if( rc != UNQLITE_OK ){ return rc; } - /* Write the raw page */ - /** CODEC */ - rc = unqliteOsWrite(pPager->pjfd,pPage->zData,pPager->iPageSize,pPager->iJournalOfft + 8); - if( rc != UNQLITE_OK ){ return rc; } - /* Compute the checksum */ - cksum = pager_cksum(pPager,pPage->zData); - rc = WriteInt32(pPager->pjfd,cksum,pPager->iJournalOfft + 8 + pPager->iPageSize); - if( rc != UNQLITE_OK ){ return rc; } - /* Update the journal offset */ - pPager->iJournalOfft += 8 /* page num */ + pPager->iPageSize + 4 /* cksum */; - pPager->nRec++; - /* Mark as journalled */ - unqliteBitvecSet(pPager->pVec,pPage->pgno); - } - } - /* Add the page to the dirty list */ - pager_page_to_dirty_list(pPager,pPage); - /* Update the database size and return. */ - if( (1 + pPage->pgno) > pPager->dbSize ){ - pPager->dbSize = 1 + pPage->pgno; - if( pPager->dbSize == SXU64_HIGH ){ - unqliteGenError(pPager->pDb,"Database maximum page limit (64-bit) reached"); - return UNQLITE_LIMIT; - } - } - return UNQLITE_OK; -} -/* -** The argument is the first in a linked list of dirty pages connected -** by the PgHdr.pDirty pointer. This function writes each one of the -** in-memory pages in the list to the database file. The argument may -** be NULL, representing an empty list. In this case this function is -** a no-op. -** -** The pager must hold at least a RESERVED lock when this function -** is called. Before writing anything to the database file, this lock -** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained, -** UNQLITE_BUSY is returned and no data is written to the database file. -*/ -static int pager_write_dirty_pages(Pager *pPager,Page *pDirty) -{ - int rc = UNQLITE_OK; - Page *pNext; - for(;;){ - if( pDirty == 0 ){ - break; - } - /* Point to the next dirty page */ - pNext = pDirty->pDirtyPrev; /* Not a bug: Reverse link */ - if( (pDirty->flags & PAGE_DONT_WRITE) == 0 ){ - rc = unqliteOsWrite(pPager->pfd,pDirty->zData,pPager->iPageSize,pDirty->pgno * pPager->iPageSize); - if( rc != UNQLITE_OK ){ - /* A rollback should be done */ - break; - } - } - /* Remove stale flags */ - pDirty->flags &= ~(PAGE_DIRTY|PAGE_DONT_WRITE|PAGE_NEED_SYNC|PAGE_IN_JOURNAL|PAGE_HOT_DIRTY); - if( pDirty->nRef < 1 ){ - /* Unlink the page now it is unused */ - pager_unlink_page(pPager,pDirty); - /* Release the page */ - pager_release_page(pPager,pDirty); - } - /* Point to the next page */ - pDirty = pNext; - } - pPager->pDirty = pPager->pFirstDirty = 0; - pPager->pHotDirty = pPager->pFirstHot = 0; - pPager->nHot = 0; - return rc; -} -/* -** The argument is the first in a linked list of hot dirty pages connected -** by the PgHdr.pHotDirty pointer. This function writes each one of the -** in-memory pages in the list to the database file. The argument may -** be NULL, representing an empty list. In this case this function is -** a no-op. -** -** The pager must hold at least a RESERVED lock when this function -** is called. Before writing anything to the database file, this lock -** is upgraded to an EXCLUSIVE lock. If the lock cannot be obtained, -** UNQLITE_BUSY is returned and no data is written to the database file. -*/ -static int pager_write_hot_dirty_pages(Pager *pPager,Page *pDirty) -{ - int rc = UNQLITE_OK; - Page *pNext; - for(;;){ - if( pDirty == 0 ){ - break; - } - /* Point to the next page */ - pNext = pDirty->pPrevHot; /* Not a bug: Reverse link */ - if( (pDirty->flags & PAGE_DONT_WRITE) == 0 ){ - rc = unqliteOsWrite(pPager->pfd,pDirty->zData,pPager->iPageSize,pDirty->pgno * pPager->iPageSize); - if( rc != UNQLITE_OK ){ - break; - } - } - /* Remove stale flags */ - pDirty->flags &= ~(PAGE_DIRTY|PAGE_DONT_WRITE|PAGE_NEED_SYNC|PAGE_IN_JOURNAL|PAGE_HOT_DIRTY); - /* Unlink from the list of dirty pages */ - if( pDirty->pDirtyPrev ){ - pDirty->pDirtyPrev->pDirtyNext = pDirty->pDirtyNext; - }else{ - pPager->pDirty = pDirty->pDirtyNext; - } - if( pDirty->pDirtyNext ){ - pDirty->pDirtyNext->pDirtyPrev = pDirty->pDirtyPrev; - }else{ - pPager->pFirstDirty = pDirty->pDirtyPrev; - } - /* Discard */ - pager_unlink_page(pPager,pDirty); - /* Release the page */ - pager_release_page(pPager,pDirty); - /* Next hot page */ - pDirty = pNext; - } - return rc; -} -/* - * Commit a transaction: Phase one. - */ -static int pager_commit_phase1(Pager *pPager) -{ - int get_excl = 0; - Page *pDirty; - int rc; - /* If no database changes have been made, return early. */ - if( pPager->iState < PAGER_WRITER_CACHEMOD ){ - return UNQLITE_OK; - } - if( pPager->is_mem ){ - /* An in-memory database */ - return UNQLITE_OK; - } - if( pPager->is_rdonly ){ - /* Read-Only DB */ - unqliteGenError(pPager->pDb,"Read-Only database"); - return UNQLITE_READ_ONLY; - } - /* Finalize the journal file */ - rc = unqliteFinalizeJournal(pPager,&get_excl,1); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Get the dirty pages */ - pDirty = pager_get_dirty_pages(pPager); - if( get_excl ){ - /* Wait one last time for the exclusive lock */ - rc = pager_wait_on_lock(pPager,EXCLUSIVE_LOCK); - if( rc != UNQLITE_OK ){ - unqliteGenError(pPager->pDb,"Cannot obtain an Exclusive lock on the target database"); - return rc; - } - } - if( pPager->iFlags & PAGER_CTRL_DIRTY_COMMIT ){ - /* Synce the database first if a dirty commit have been applied */ - unqliteOsSync(pPager->pfd,UNQLITE_SYNC_NORMAL); - } - /* Write the dirty pages */ - rc = pager_write_dirty_pages(pPager,pDirty); - if( rc != UNQLITE_OK ){ - /* Rollback your DB */ - pPager->iFlags |= PAGER_CTRL_COMMIT_ERR; - pPager->pFirstDirty = pDirty; - unqliteGenError(pPager->pDb,"IO error while writing dirty pages, rollback your database"); - return rc; - } - /* If the file on disk is not the same size as the database image, - * then use unqliteOsTruncate to grow or shrink the file here. - */ - if( pPager->dbSize != pPager->dbOrigSize ){ - unqliteOsTruncate(pPager->pfd,pPager->iPageSize * pPager->dbSize); - } - /* Sync the database file */ - unqliteOsSync(pPager->pfd,UNQLITE_SYNC_FULL); - /* Remove stale flags */ - pPager->iJournalOfft = 0; - pPager->nRec = 0; - return UNQLITE_OK; -} -/* - * Commit a transaction: Phase two. - */ -static int pager_commit_phase2(Pager *pPager) -{ - if( !pPager->is_mem ){ - if( pPager->iState == PAGER_OPEN ){ - return UNQLITE_OK; - } - if( pPager->iState != PAGER_READER ){ - if( !pPager->no_jrnl ){ - /* Finally, unlink the journal file */ - unqliteOsDelete(pPager->pVfs,pPager->zJournal,1); - } - /* Downgrade to shraed lock */ - pager_unlock_db(pPager,SHARED_LOCK); - pPager->iState = PAGER_READER; - if( pPager->pVec ){ - unqliteBitvecDestroy(pPager->pVec); - pPager->pVec = 0; - } - } - } - return UNQLITE_OK; -} -/* - * Perform a dirty commit. - */ -static int pager_dirty_commit(Pager *pPager) -{ - int get_excl = 0; - Page *pHot; - int rc; - /* Finalize the journal file without closing it */ - rc = unqliteFinalizeJournal(pPager,&get_excl,0); - if( rc != UNQLITE_OK ){ - /* It's not a fatal error if something goes wrong here since - * its not the final commit. - */ - return UNQLITE_OK; - } - /* Point to the list of hot pages */ - pHot = pager_get_hot_pages(pPager); - if( pHot == 0 ){ - return UNQLITE_OK; - } - if( get_excl ){ - /* Wait one last time for the exclusive lock */ - rc = pager_wait_on_lock(pPager,EXCLUSIVE_LOCK); - if( rc != UNQLITE_OK ){ - /* Not so fatal, will try another time */ - return UNQLITE_OK; - } - } - /* Tell that a dirty commit happen */ - pPager->iFlags |= PAGER_CTRL_DIRTY_COMMIT; - /* Write the hot pages now */ - rc = pager_write_hot_dirty_pages(pPager,pHot); - if( rc != UNQLITE_OK ){ - pPager->iFlags |= PAGER_CTRL_COMMIT_ERR; - unqliteGenError(pPager->pDb,"IO error while writing hot dirty pages, rollback your database"); - return rc; - } - pPager->pFirstHot = pPager->pHotDirty = 0; - pPager->nHot = 0; - /* No need to sync the database file here, since the journal is already - * open here and this is not the final commit. - */ - return UNQLITE_OK; -} -/* -** Commit a transaction and sync the database file for the pager pPager. -** -** This routine ensures that: -** -** * the journal is synced, -** * all dirty pages are written to the database file, -** * the database file is truncated (if required), and -** * the database file synced. -** * the journal file is deleted. -*/ -UNQLITE_PRIVATE int unqlitePagerCommit(Pager *pPager) -{ - int rc; - /* Commit: Phase One */ - rc = pager_commit_phase1(pPager); - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Commit: Phase Two */ - rc = pager_commit_phase2(pPager); - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Remove stale flags */ - pPager->iFlags &= ~PAGER_CTRL_COMMIT_ERR; - /* All done */ - return UNQLITE_OK; -fail: - /* Disable the auto-commit flag */ - pPager->pDb->iFlags |= UNQLITE_FL_DISABLE_AUTO_COMMIT; - return rc; -} -/* - * Reset the pager to its initial state. This is caused by - * a rollback operation. - */ -static int pager_reset_state(Pager *pPager,int bResetKvEngine) -{ - unqlite_kv_engine *pEngine = pPager->pEngine; - Page *pNext,*pPtr = pPager->pAll; - const unqlite_kv_io *pIo; - int rc; - /* Remove stale flags */ - pPager->iFlags &= ~(PAGER_CTRL_COMMIT_ERR|PAGER_CTRL_DIRTY_COMMIT); - pPager->iJournalOfft = 0; - pPager->nRec = 0; - /* Database original size */ - pPager->dbSize = pPager->dbOrigSize; - /* Discard all in-memory pages */ - for(;;){ - if( pPtr == 0 ){ - break; - } - pNext = pPtr->pNext; /* Reverse link */ - /* Remove stale flags */ - pPtr->flags &= ~(PAGE_DIRTY|PAGE_DONT_WRITE|PAGE_NEED_SYNC|PAGE_IN_JOURNAL|PAGE_HOT_DIRTY); - /* Release the page */ - pager_release_page(pPager,pPtr); - /* Point to the next page */ - pPtr = pNext; - } - pPager->pAll = 0; - pPager->nPage = 0; - pPager->pDirty = pPager->pFirstDirty = 0; - pPager->pHotDirty = pPager->pFirstHot = 0; - pPager->nHot = 0; - if( pPager->apHash ){ - /* Zero the table */ - SyZero((void *)pPager->apHash,sizeof(Page *) * pPager->nSize); - } - if( pPager->pVec ){ - unqliteBitvecDestroy(pPager->pVec); - pPager->pVec = 0; - } - /* Switch back to shared lock */ - pager_unlock_db(pPager,SHARED_LOCK); - pPager->iState = PAGER_READER; - if( bResetKvEngine ){ - /* Reset the underlying KV engine */ - pIo = pEngine->pIo; - if( pIo->pMethods->xRelease ){ - /* Call the release callback */ - pIo->pMethods->xRelease(pEngine); - } - /* Zero the structure */ - SyZero(pEngine,(sxu32)pIo->pMethods->szKv); - /* Fill in */ - pEngine->pIo = pIo; - if( pIo->pMethods->xInit ){ - /* Call the init method */ - rc = pIo->pMethods->xInit(pEngine,pPager->iPageSize); - if( rc != UNQLITE_OK ){ - return rc; - } - } - if( pIo->pMethods->xOpen ){ - /* Call the xOpen method */ - rc = pIo->pMethods->xOpen(pEngine,pPager->dbSize); - if( rc != UNQLITE_OK ){ - return rc; - } - } - } - /* All done */ - return UNQLITE_OK; -} -/* -** If a write transaction is open, then all changes made within the -** transaction are reverted and the current write-transaction is closed. -** The pager falls back to PAGER_READER state if successful. -** -** Otherwise, in rollback mode, this function performs two functions: -** -** 1) It rolls back the journal file, restoring all database file and -** in-memory cache pages to the state they were in when the transaction -** was opened, and -** -** 2) It finalizes the journal file, so that it is not used for hot -** rollback at any point in the future (i.e. deletion). -** -** Finalization of the journal file (task 2) is only performed if the -** rollback is successful. -** -*/ -UNQLITE_PRIVATE int unqlitePagerRollback(Pager *pPager,int bResetKvEngine) -{ - int rc = UNQLITE_OK; - if( pPager->iState < PAGER_WRITER_LOCKED ){ - /* A write transaction must be opened */ - return UNQLITE_OK; - } - if( pPager->is_mem ){ - /* As of this release 1.1.6: Transactions are not supported for in-memory databases */ - return UNQLITE_OK; - } - if( pPager->is_rdonly ){ - /* Read-Only DB */ - unqliteGenError(pPager->pDb,"Read-Only database"); - return UNQLITE_READ_ONLY; - } - if( pPager->iState >= PAGER_WRITER_CACHEMOD ){ - if( !pPager->no_jrnl ){ - /* Close any outstanding joural file */ - if( pPager->pjfd ){ - /* Sync the journal file */ - unqliteOsSync(pPager->pjfd,UNQLITE_SYNC_NORMAL); - } - unqliteOsCloseFree(pPager->pAllocator,pPager->pjfd); - pPager->pjfd = 0; - if( pPager->iFlags & (PAGER_CTRL_COMMIT_ERR|PAGER_CTRL_DIRTY_COMMIT) ){ - /* Perform the rollback */ - rc = pager_journal_rollback(pPager,0); - if( rc != UNQLITE_OK ){ - /* Set the auto-commit flag */ - pPager->pDb->iFlags |= UNQLITE_FL_DISABLE_AUTO_COMMIT; - return rc; - } - } - } - /* Unlink the journal file */ - unqliteOsDelete(pPager->pVfs,pPager->zJournal,1); - /* Reset the pager state */ - rc = pager_reset_state(pPager,bResetKvEngine); - if( rc != UNQLITE_OK ){ - /* Mostly an unlikely scenario */ - pPager->pDb->iFlags |= UNQLITE_FL_DISABLE_AUTO_COMMIT; /* Set the auto-commit flag */ - unqliteGenError(pPager->pDb,"Error while reseting pager to its initial state"); - return rc; - } - }else{ - /* Downgrade to shared lock */ - pager_unlock_db(pPager,SHARED_LOCK); - pPager->iState = PAGER_READER; - } - return UNQLITE_OK; -} -/* - * Mark a data page as non writeable. - */ -static int unqlitePagerDontWrite(unqlite_page *pMyPage) -{ - Page *pPage = (Page *)pMyPage; - if( pPage->pgno > 0 /* Page 0 is always writeable */ ){ - pPage->flags |= PAGE_DONT_WRITE; - } - return UNQLITE_OK; -} -/* -** Mark a data page as writeable. This routine must be called before -** making changes to a page. The caller must check the return value -** of this function and be careful not to change any page data unless -** this routine returns UNQLITE_OK. -*/ -static int unqlitePageWrite(unqlite_page *pMyPage) -{ - Page *pPage = (Page *)pMyPage; - Pager *pPager = pPage->pPager; - int rc; - /* Begin the write transaction */ - rc = unqlitePagerBegin(pPager); - if( rc != UNQLITE_OK ){ - return rc; - } - if( pPager->iState == PAGER_WRITER_LOCKED ){ - /* The journal file needs to be opened. Higher level routines have already - ** obtained the necessary locks to begin the write-transaction, but the - ** rollback journal might not yet be open. Open it now if this is the case. - */ - rc = unqliteOpenJournal(pPager); - if( rc != UNQLITE_OK ){ - return rc; - } - } - if( pPager->nHot > 127 ){ - /* Write hot dirty pages */ - rc = pager_dirty_commit(pPager); - if( rc != UNQLITE_OK ){ - /* A rollback must be done */ - unqliteGenError(pPager->pDb,"Please perform a rollback"); - return rc; - } - } - /* Write the page to the journal file */ - rc = page_write(pPager,pPage); - return rc; -} -/* -** Acquire a reference to page number pgno in pager pPager (a page -** reference has type unqlite_page*). If the requested reference is -** successfully obtained, it is copied to *ppPage and UNQLITE_OK returned. -** -** If the requested page is already in the cache, it is returned. -** Otherwise, a new page object is allocated and populated with data -** read from the database file. -*/ -static int unqlitePagerAcquire( - Pager *pPager, /* The pager open on the database file */ - pgno pgno, /* Page number to fetch */ - unqlite_page **ppPage, /* OUT: Acquired page */ - int fetchOnly, /* Cache lookup only */ - int noContent /* Do not bother reading content from disk if true */ -) -{ - Page *pPage; - int rc; - /* Acquire a shared lock (if not yet done) on the database and rollback any hot-journal if present */ - rc = pager_shared_lock(pPager); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Fetch the page from the cache */ - pPage = pager_fetch_page(pPager,pgno); - if( fetchOnly ){ - if( ppPage ){ - *ppPage = (unqlite_page *)pPage; - } - return pPage ? UNQLITE_OK : UNQLITE_NOTFOUND; - } - if( pPage == 0 ){ - /* Allocate a new page */ - pPage = pager_alloc_page(pPager,pgno); - if( pPage == 0 ){ - unqliteGenOutofMem(pPager->pDb); - return UNQLITE_NOMEM; - } - /* Read page contents */ - rc = pager_get_page_contents(pPager,pPage,noContent); - if( rc != UNQLITE_OK ){ - SyMemBackendPoolFree(pPager->pAllocator,pPage); - return rc; - } - /* Link the page */ - pager_link_page(pPager,pPage); - }else{ - if( ppPage ){ - page_ref(pPage); - } - } - /* All done, page is loaded in memeory */ - if( ppPage ){ - *ppPage = (unqlite_page *)pPage; - } - return UNQLITE_OK; -} -/* - * Return true if we are dealing with an in-memory database. - */ -static int unqliteInMemory(const char *zFilename) -{ - sxu32 n; - if( SX_EMPTY_STR(zFilename) ){ - /* NULL or the empty string means an in-memory database */ - return TRUE; - } - n = SyStrlen(zFilename); - if( n == sizeof(":mem:") - 1 && - SyStrnicmp(zFilename,":mem:",sizeof(":mem:") - 1) == 0 ){ - return TRUE; - } - if( n == sizeof(":memory:") - 1 && - SyStrnicmp(zFilename,":memory:",sizeof(":memory:") - 1) == 0 ){ - return TRUE; - } - return FALSE; -} -/* - * Allocate a new KV cursor. - */ -UNQLITE_PRIVATE int unqliteInitCursor(unqlite *pDb,unqlite_kv_cursor **ppOut) -{ - unqlite_kv_methods *pMethods; - unqlite_kv_cursor *pCur; - sxu32 nByte; - /* Storage engine methods */ - pMethods = pDb->sDB.pPager->pEngine->pIo->pMethods; - if( pMethods->szCursor < 1 ){ - /* Implementation does not supprt cursors */ - unqliteGenErrorFormat(pDb,"Storage engine '%s' does not support cursors",pMethods->zName); - return UNQLITE_NOTIMPLEMENTED; - } - nByte = pMethods->szCursor; - if( nByte < sizeof(unqlite_kv_cursor) ){ - nByte += sizeof(unqlite_kv_cursor); - } - pCur = (unqlite_kv_cursor *)SyMemBackendPoolAlloc(&pDb->sMem,nByte); - if( pCur == 0 ){ - unqliteGenOutofMem(pDb); - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pCur,nByte); - /* Save the cursor */ - pCur->pStore = pDb->sDB.pPager->pEngine; - /* Invoke the initialization callback if any */ - if( pMethods->xCursorInit ){ - pMethods->xCursorInit(pCur); - } - /* All done */ - *ppOut = pCur; - return UNQLITE_OK; -} -/* - * Release a cursor. - */ -UNQLITE_PRIVATE int unqliteReleaseCursor(unqlite *pDb,unqlite_kv_cursor *pCur) -{ - unqlite_kv_methods *pMethods; - /* Storage engine methods */ - pMethods = pDb->sDB.pPager->pEngine->pIo->pMethods; - /* Invoke the release callback if available */ - if( pMethods->xCursorRelease ){ - pMethods->xCursorRelease(pCur); - } - /* Finally, free the whole instance */ - SyMemBackendPoolFree(&pDb->sMem,pCur); - return UNQLITE_OK; -} -/* - * Release the underlying KV storage engine and invoke - * its associated callbacks if available. - */ -static void pager_release_kv_engine(Pager *pPager) -{ - unqlite_kv_engine *pEngine = pPager->pEngine; - unqlite_db *pStorage = &pPager->pDb->sDB; - if( pStorage->pCursor ){ - /* Release the associated cursor */ - unqliteReleaseCursor(pPager->pDb,pStorage->pCursor); - pStorage->pCursor = 0; - } - if( pEngine->pIo->pMethods->xRelease ){ - pEngine->pIo->pMethods->xRelease(pEngine); - } - /* Release the whole instance */ - SyMemBackendFree(&pPager->pDb->sMem,(void *)pEngine->pIo); - SyMemBackendFree(&pPager->pDb->sMem,(void *)pEngine); - pPager->pEngine = 0; -} -/* Forward declaration */ -static int pager_kv_io_init(Pager *pPager,unqlite_kv_methods *pMethods,unqlite_kv_io *pIo); -/* - * Allocate, initialize and register a new KV storage engine - * within this database instance. - */ -UNQLITE_PRIVATE int unqlitePagerRegisterKvEngine(Pager *pPager,unqlite_kv_methods *pMethods) -{ - unqlite_db *pStorage = &pPager->pDb->sDB; - unqlite *pDb = pPager->pDb; - unqlite_kv_engine *pEngine; - unqlite_kv_io *pIo; - sxu32 nByte; - int rc; - if( pPager->pEngine ){ - if( pMethods == pPager->pEngine->pIo->pMethods ){ - /* Ticket 1432: Same implementation */ - return UNQLITE_OK; - } - /* Release the old KV engine */ - pager_release_kv_engine(pPager); - } - /* Allocate a new KV engine instance */ - nByte = (sxu32)pMethods->szKv; - pEngine = (unqlite_kv_engine *)SyMemBackendAlloc(&pDb->sMem,nByte); - if( pEngine == 0 ){ - unqliteGenOutofMem(pDb); - return UNQLITE_NOMEM; - } - pIo = (unqlite_kv_io *)SyMemBackendAlloc(&pDb->sMem,sizeof(unqlite_kv_io)); - if( pIo == 0 ){ - SyMemBackendFree(&pDb->sMem,pEngine); - unqliteGenOutofMem(pDb); - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pIo,sizeof(unqlite_io_methods)); - SyZero(pEngine,nByte); - /* Populate the IO structure */ - pager_kv_io_init(pPager,pMethods,pIo); - pEngine->pIo = pIo; - /* Invoke the init callback if avaialble */ - if( pMethods->xInit ){ - rc = pMethods->xInit(pEngine,unqliteGetPageSize()); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pDb, - "xInit() method of the underlying KV engine '%z' failed",&pPager->sKv); - goto fail; - } - pEngine->pIo = pIo; - } - pPager->pEngine = pEngine; - /* Allocate a new cursor */ - rc = unqliteInitCursor(pDb,&pStorage->pCursor); - if( rc != UNQLITE_OK ){ - goto fail; - } - return UNQLITE_OK; -fail: - SyMemBackendFree(&pDb->sMem,pEngine); - SyMemBackendFree(&pDb->sMem,pIo); - return rc; -} -/* - * Return the underlying KV storage engine instance. - */ -UNQLITE_PRIVATE unqlite_kv_engine * unqlitePagerGetKvEngine(unqlite *pDb) -{ - return pDb->sDB.pPager->pEngine; -} -/* -* Allocate and initialize a new Pager object. The pager should -* eventually be freed by passing it to unqlitePagerClose(). -* -* The zFilename argument is the path to the database file to open. -* If zFilename is NULL or ":memory:" then all information is held -* in cache. It is never written to disk. This can be used to implement -* an in-memory database. -*/ -UNQLITE_PRIVATE int unqlitePagerOpen( - unqlite_vfs *pVfs, /* The virtual file system to use */ - unqlite *pDb, /* Database handle */ - const char *zFilename, /* Name of the database file to open */ - unsigned int iFlags /* flags controlling this file */ - ) -{ - unqlite_kv_methods *pMethods = 0; - int is_mem,rd_only,no_jrnl; - Pager *pPager; - sxu32 nByte; - sxu32 nLen; - int rc; - - /* Select the appropriate KV storage subsytem */ - if( (iFlags & UNQLITE_OPEN_IN_MEMORY) || unqliteInMemory(zFilename) ){ - /* An in-memory database, record that */ - pMethods = unqliteFindKVStore("mem",sizeof("mem") - 1); /* Always available */ - iFlags |= UNQLITE_OPEN_IN_MEMORY; - }else{ - /* Install the default key value storage subsystem [i.e. Linear Hash] */ - pMethods = unqliteFindKVStore("hash",sizeof("hash")-1); - if( pMethods == 0 ){ - /* Use the b+tree storage backend if the linear hash storage is not available */ - pMethods = unqliteFindKVStore("btree",sizeof("btree")-1); - } - } - if( pMethods == 0 ){ - /* Can't happen */ - unqliteGenError(pDb,"Cannot install a default Key/Value storage engine"); - return UNQLITE_NOTIMPLEMENTED; - } - is_mem = (iFlags & UNQLITE_OPEN_IN_MEMORY) != 0; - rd_only = (iFlags & UNQLITE_OPEN_READONLY) != 0; - no_jrnl = (iFlags & UNQLITE_OPEN_OMIT_JOURNALING) != 0; - rc = UNQLITE_OK; - if( is_mem ){ - /* Omit journaling for in-memory database */ - no_jrnl = 1; - } - /* Total number of bytes to allocate */ - nByte = sizeof(Pager); - nLen = 0; - if( !is_mem ){ - nLen = SyStrlen(zFilename); - nByte += pVfs->mxPathname + nLen + sizeof(char) /* null termniator */; - } - /* Allocate */ - pPager = (Pager *)SyMemBackendAlloc(&pDb->sMem,nByte); - if( pPager == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pPager,nByte); - /* Fill-in the structure */ - pPager->pAllocator = &pDb->sMem; - pPager->pDb = pDb; - pDb->sDB.pPager = pPager; - /* Allocate page table */ - pPager->nSize = 128; /* Must be a power of two */ - nByte = pPager->nSize * sizeof(Page *); - pPager->apHash = (Page **)SyMemBackendAlloc(pPager->pAllocator,nByte); - if( pPager->apHash == 0 ){ - rc = UNQLITE_NOMEM; - goto fail; - } - SyZero(pPager->apHash,nByte); - pPager->is_mem = is_mem; - pPager->no_jrnl = no_jrnl; - pPager->is_rdonly = rd_only; - pPager->iOpenFlags = iFlags; - pPager->pVfs = pVfs; - SyRandomnessInit(&pPager->sPrng,0,0); - SyRandomness(&pPager->sPrng,(void *)&pPager->cksumInit,sizeof(sxu32)); - /* Unlimited cache size */ - pPager->nCacheMax = SXU32_HIGH; - /* Copy filename and journal name */ - if( !is_mem ){ - pPager->zFilename = (char *)&pPager[1]; - rc = UNQLITE_OK; - if( pVfs->xFullPathname ){ - rc = pVfs->xFullPathname(pVfs,zFilename,pVfs->mxPathname + nLen,pPager->zFilename); - } - if( rc != UNQLITE_OK ){ - /* Simple filename copy */ - SyMemcpy(zFilename,pPager->zFilename,nLen); - pPager->zFilename[nLen] = 0; - rc = UNQLITE_OK; - }else{ - nLen = SyStrlen(pPager->zFilename); - } - pPager->zJournal = (char *) SyMemBackendAlloc(pPager->pAllocator,nLen + sizeof(UNQLITE_JOURNAL_FILE_SUFFIX) + sizeof(char)); - if( pPager->zJournal == 0 ){ - rc = UNQLITE_NOMEM; - goto fail; - } - /* Copy filename */ - SyMemcpy(pPager->zFilename,pPager->zJournal,nLen); - /* Copy journal suffix */ - SyMemcpy(UNQLITE_JOURNAL_FILE_SUFFIX,&pPager->zJournal[nLen],sizeof(UNQLITE_JOURNAL_FILE_SUFFIX)-1); - /* Append the nul terminator to the journal path */ - pPager->zJournal[nLen + ( sizeof(UNQLITE_JOURNAL_FILE_SUFFIX) - 1)] = 0; - } - /* Finally, register the selected KV engine */ - rc = unqlitePagerRegisterKvEngine(pPager,pMethods); - if( rc != UNQLITE_OK ){ - goto fail; - } - /* Set the pager state */ - if( pPager->is_mem ){ - pPager->iState = PAGER_WRITER_FINISHED; - pPager->iLock = EXCLUSIVE_LOCK; - }else{ - pPager->iState = PAGER_OPEN; - pPager->iLock = NO_LOCK; - } - /* All done, ready for processing */ - return UNQLITE_OK; -fail: - SyMemBackendFree(&pDb->sMem,pPager); - return rc; -} -/* - * Set a cache limit. Note that, this is a simple hint, the pager is not - * forced to honor this limit. - */ -UNQLITE_PRIVATE int unqlitePagerSetCachesize(Pager *pPager,int mxPage) -{ - if( mxPage < 256 ){ - return UNQLITE_INVALID; - } - pPager->nCacheMax = mxPage; - return UNQLITE_OK; -} -/* - * Shutdown the page cache. Free all memory and close the database file. - */ -UNQLITE_PRIVATE int unqlitePagerClose(Pager *pPager) -{ - /* Release the KV engine */ - pager_release_kv_engine(pPager); - if( pPager->iOpenFlags & UNQLITE_OPEN_MMAP ){ - const jx9_vfs *pVfs = jx9ExportBuiltinVfs(); - if( pVfs && pVfs->xUnmap && pPager->pMmap ){ - pVfs->xUnmap(pPager->pMmap,pPager->dbByteSize); - } - } - if( !pPager->is_mem && pPager->iState > PAGER_OPEN ){ - /* Release all lock on this database handle */ - pager_unlock_db(pPager,NO_LOCK); - /* Close the file */ - unqliteOsCloseFree(pPager->pAllocator,pPager->pfd); - } - if( pPager->pVec ){ - unqliteBitvecDestroy(pPager->pVec); - pPager->pVec = 0; - } - return UNQLITE_OK; -} -/* - * Generate a random string. - */ -UNQLITE_PRIVATE void unqlitePagerRandomString(Pager *pPager,char *zBuf,sxu32 nLen) -{ - static const char zBase[] = {"abcdefghijklmnopqrstuvwxyz"}; /* English Alphabet */ - sxu32 i; - /* Generate a binary string first */ - SyRandomness(&pPager->sPrng,zBuf,nLen); - /* Turn the binary string into english based alphabet */ - for( i = 0 ; i < nLen ; ++i ){ - zBuf[i] = zBase[zBuf[i] % (sizeof(zBase)-1)]; - } -} -/* - * Generate a random number. - */ -UNQLITE_PRIVATE sxu32 unqlitePagerRandomNum(Pager *pPager) -{ - sxu32 iNum; - SyRandomness(&pPager->sPrng,(void *)&iNum,sizeof(iNum)); - return iNum; -} -/* Exported KV IO Methods */ -/* - * Refer to [unqlitePagerAcquire()] - */ -static int unqliteKvIoPageGet(unqlite_kv_handle pHandle,pgno iNum,unqlite_page **ppPage) -{ - int rc; - rc = unqlitePagerAcquire((Pager *)pHandle,iNum,ppPage,0,0); - return rc; -} -/* - * Refer to [unqlitePagerAcquire()] - */ -static int unqliteKvIoPageLookup(unqlite_kv_handle pHandle,pgno iNum,unqlite_page **ppPage) -{ - int rc; - rc = unqlitePagerAcquire((Pager *)pHandle,iNum,ppPage,1,0); - return rc; -} -/* - * Refer to [unqlitePagerAcquire()] - */ -static int unqliteKvIoNewPage(unqlite_kv_handle pHandle,unqlite_page **ppPage) -{ - Pager *pPager = (Pager *)pHandle; - int rc; - /* - * Acquire a reader-lock first so that pPager->dbSize get initialized. - */ - rc = pager_shared_lock(pPager); - if( rc == UNQLITE_OK ){ - rc = unqlitePagerAcquire(pPager,pPager->dbSize == 0 ? /* Page 0 is reserved */ 1 : pPager->dbSize ,ppPage,0,0); - } - return rc; -} -/* - * Refer to [unqlitePageWrite()] - */ -static int unqliteKvIopageWrite(unqlite_page *pPage) -{ - int rc; - if( pPage == 0 ){ - /* TICKET 1433-0348 */ - return UNQLITE_OK; - } - rc = unqlitePageWrite(pPage); - return rc; -} -/* - * Refer to [unqlitePagerDontWrite()] - */ -static int unqliteKvIoPageDontWrite(unqlite_page *pPage) -{ - int rc; - if( pPage == 0 ){ - /* TICKET 1433-0348 */ - return UNQLITE_OK; - } - rc = unqlitePagerDontWrite(pPage); - return rc; -} -/* - * Refer to [unqliteBitvecSet()] - */ -static int unqliteKvIoPageDontJournal(unqlite_page *pRaw) -{ - Page *pPage = (Page *)pRaw; - Pager *pPager; - if( pPage == 0 ){ - /* TICKET 1433-0348 */ - return UNQLITE_OK; - } - pPager = pPage->pPager; - if( pPager->iState >= PAGER_WRITER_LOCKED ){ - if( !pPager->no_jrnl && pPager->pVec && !unqliteBitvecTest(pPager->pVec,pPage->pgno) ){ - unqliteBitvecSet(pPager->pVec,pPage->pgno); - } - } - return UNQLITE_OK; -} -/* - * Do not add a page to the hot dirty list. - */ -static int unqliteKvIoPageDontMakeHot(unqlite_page *pRaw) -{ - Page *pPage = (Page *)pRaw; - - if( pPage == 0 ){ - /* TICKET 1433-0348 */ - return UNQLITE_OK; - } - pPage->flags |= PAGE_DONT_MAKE_HOT; - - /* Remove from hot dirty list if it is already there */ - if( pPage->flags & PAGE_HOT_DIRTY ){ - Pager *pPager = pPage->pPager; - if( pPage->pNextHot ){ - pPage->pNextHot->pPrevHot = pPage->pPrevHot; - } - if( pPage->pPrevHot ){ - pPage->pPrevHot->pNextHot = pPage->pNextHot; - } - if( pPager->pFirstHot == pPage ){ - pPager->pFirstHot = pPage->pPrevHot; - } - if( pPager->pHotDirty == pPage ){ - pPager->pHotDirty = pPage->pNextHot; - } - pPager->nHot--; - pPage->flags &= ~PAGE_HOT_DIRTY; - } - - return UNQLITE_OK; -} -/* - * Refer to [page_ref()] - */ -static int unqliteKvIopage_ref(unqlite_page *pPage) -{ - if( pPage ){ - page_ref((Page *)pPage); - } - return UNQLITE_OK; -} -/* - * Refer to [page_unref()] - */ -static int unqliteKvIoPageUnRef(unqlite_page *pPage) -{ - if( pPage ){ - page_unref((Page *)pPage); - } - return UNQLITE_OK; -} -/* - * Refer to the declaration of the [Pager] structure - */ -static int unqliteKvIoReadOnly(unqlite_kv_handle pHandle) -{ - return ((Pager *)pHandle)->is_rdonly; -} -/* - * Refer to the declaration of the [Pager] structure - */ -static int unqliteKvIoPageSize(unqlite_kv_handle pHandle) -{ - return ((Pager *)pHandle)->iPageSize; -} -/* - * Refer to the declaration of the [Pager] structure - */ -static unsigned char * unqliteKvIoTempPage(unqlite_kv_handle pHandle) -{ - return ((Pager *)pHandle)->zTmpPage; -} -/* - * Set a page unpin callback. - * Refer to the declaration of the [Pager] structure - */ -static void unqliteKvIoPageUnpin(unqlite_kv_handle pHandle,void (*xPageUnpin)(void *)) -{ - Pager *pPager = (Pager *)pHandle; - pPager->xPageUnpin = xPageUnpin; -} -/* - * Set a page reload callback. - * Refer to the declaration of the [Pager] structure - */ -static void unqliteKvIoPageReload(unqlite_kv_handle pHandle,void (*xPageReload)(void *)) -{ - Pager *pPager = (Pager *)pHandle; - pPager->xPageReload = xPageReload; -} -/* - * Log an error. - * Refer to the declaration of the [Pager] structure - */ -static void unqliteKvIoErr(unqlite_kv_handle pHandle,const char *zErr) -{ - Pager *pPager = (Pager *)pHandle; - unqliteGenError(pPager->pDb,zErr); -} -/* - * Init an instance of the [unqlite_kv_io] structure. - */ -static int pager_kv_io_init(Pager *pPager,unqlite_kv_methods *pMethods,unqlite_kv_io *pIo) -{ - pIo->pHandle = pPager; - pIo->pMethods = pMethods; - - pIo->xGet = unqliteKvIoPageGet; - pIo->xLookup = unqliteKvIoPageLookup; - pIo->xNew = unqliteKvIoNewPage; - - pIo->xWrite = unqliteKvIopageWrite; - pIo->xDontWrite = unqliteKvIoPageDontWrite; - pIo->xDontJournal = unqliteKvIoPageDontJournal; - pIo->xDontMkHot = unqliteKvIoPageDontMakeHot; - - pIo->xPageRef = unqliteKvIopage_ref; - pIo->xPageUnref = unqliteKvIoPageUnRef; - - pIo->xPageSize = unqliteKvIoPageSize; - pIo->xReadOnly = unqliteKvIoReadOnly; - - pIo->xTmpPage = unqliteKvIoTempPage; - - pIo->xSetUnpin = unqliteKvIoPageUnpin; - pIo->xSetReload = unqliteKvIoPageReload; - - pIo->xErr = unqliteKvIoErr; - - return UNQLITE_OK; -} -/* - * ---------------------------------------------------------- - * File: unqlite_vm.c - * MD5: 2a0c56efb2ab87d3e52d0d7c3147c53b - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: unqlite_vm.c v1.0 Win7 2013-01-29 23:37 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* This file deals with low level stuff related to the unQLite Virtual Machine */ - -/* Record ID as a hash value */ -#define COL_RECORD_HASH(RID) (RID) -/* - * Fetch a record from a given collection. - */ -static unqlite_col_record * CollectionCacheFetchRecord( - unqlite_col *pCol, /* Target collection */ - jx9_int64 nId /* Unique record ID */ - ) -{ - unqlite_col_record *pEntry; - if( pCol->nRec < 1 ){ - /* Don't bother hashing */ - return 0; - } - pEntry = pCol->apRecord[COL_RECORD_HASH(nId) & (pCol->nRecSize - 1)]; - for(;;){ - if( pEntry == 0 ){ - break; - } - if( pEntry->nId == nId ){ - /* Record found */ - return pEntry; - } - /* Point to the next entry */ - pEntry = pEntry->pNextCol; - - } - /* No such record */ - return 0; -} -/* - * Install a freshly created record in a given collection. - */ -static int CollectionCacheInstallRecord( - unqlite_col *pCol, /* Target collection */ - jx9_int64 nId, /* Unique record ID */ - jx9_value *pValue /* JSON value */ - ) -{ - unqlite_col_record *pRecord; - sxu32 iBucket; - /* Fetch the record first */ - pRecord = CollectionCacheFetchRecord(pCol,nId); - if( pRecord ){ - /* Record already installed, overwrite its old value */ - jx9MemObjStore(pValue,&pRecord->sValue); - return UNQLITE_OK; - } - /* Allocate a new instance */ - pRecord = (unqlite_col_record *)SyMemBackendPoolAlloc(&pCol->pVm->sAlloc,sizeof(unqlite_col_record)); - if( pRecord == 0 ){ - return UNQLITE_NOMEM; - } - /* Zero the structure */ - SyZero(pRecord,sizeof(unqlite_col_record)); - /* Fill in the structure */ - jx9MemObjInit(pCol->pVm->pJx9Vm,&pRecord->sValue); - jx9MemObjStore(pValue,&pRecord->sValue); - pRecord->nId = nId; - pRecord->pCol = pCol; - /* Install in the corresponding bucket */ - iBucket = COL_RECORD_HASH(nId) & (pCol->nRecSize - 1); - pRecord->pNextCol = pCol->apRecord[iBucket]; - if( pCol->apRecord[iBucket] ){ - pCol->apRecord[iBucket]->pPrevCol = pRecord; - } - pCol->apRecord[iBucket] = pRecord; - /* Link */ - MACRO_LD_PUSH(pCol->pList,pRecord); - pCol->nRec++; - if( (pCol->nRec >= pCol->nRecSize * 3) && pCol->nRec < 100000 ){ - /* Allocate a new larger table */ - sxu32 nNewSize = pCol->nRecSize << 1; - unqlite_col_record *pEntry; - unqlite_col_record **apNew; - sxu32 n; - - apNew = (unqlite_col_record **)SyMemBackendAlloc(&pCol->pVm->sAlloc, nNewSize * sizeof(unqlite_col_record *)); - if( apNew ){ - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(unqlite_col_record *)); - /* Rehash all entries */ - n = 0; - pEntry = pCol->pList; - for(;;){ - /* Loop one */ - if( n >= pCol->nRec ){ - break; - } - pEntry->pNextCol = pEntry->pPrevCol = 0; - /* Install in the new bucket */ - iBucket = COL_RECORD_HASH(pEntry->nId) & (nNewSize - 1); - pEntry->pNextCol = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevCol = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(&pCol->pVm->sAlloc,(void *)pCol->apRecord); - pCol->apRecord = apNew; - pCol->nRecSize = nNewSize; - } - } - /* All done */ - return UNQLITE_OK; -} -/* - * Remove a record from the collection table. - */ -UNQLITE_PRIVATE int unqliteCollectionCacheRemoveRecord( - unqlite_col *pCol, /* Target collection */ - jx9_int64 nId /* Unique record ID */ - ) -{ - unqlite_col_record *pRecord; - /* Fetch the record first */ - pRecord = CollectionCacheFetchRecord(pCol,nId); - if( pRecord == 0 ){ - /* No such record */ - return UNQLITE_NOTFOUND; - } - if( pRecord->pPrevCol ){ - pRecord->pPrevCol->pNextCol = pRecord->pNextCol; - }else{ - sxu32 iBucket = COL_RECORD_HASH(nId) & (pCol->nRecSize - 1); - pCol->apRecord[iBucket] = pRecord->pNextCol; - } - if( pRecord->pNextCol ){ - pRecord->pNextCol->pPrevCol = pRecord->pPrevCol; - } - /* Unlink */ - MACRO_LD_REMOVE(pCol->pList,pRecord); - pCol->nRec--; - return UNQLITE_OK; -} -/* - * Discard a collection and its records. - */ -static int CollectionCacheRelease(unqlite_col *pCol) -{ - unqlite_col_record *pNext,*pRec = pCol->pList; - unqlite_vm *pVm = pCol->pVm; - sxu32 n; - /* Discard all records */ - for( n = 0 ; n < pCol->nRec ; ++n ){ - pNext = pRec->pNext; - jx9MemObjRelease(&pRec->sValue); - SyMemBackendPoolFree(&pVm->sAlloc,(void *)pRec); - /* Point to the next record */ - pRec = pNext; - } - SyMemBackendFree(&pVm->sAlloc,(void *)pCol->apRecord); - pCol->nRec = pCol->nRecSize = 0; - pCol->pList = 0; - return UNQLITE_OK; -} -/* - * Install a freshly created collection in the unqlite VM. - */ -static int unqliteVmInstallCollection( - unqlite_vm *pVm, /* Target VM */ - unqlite_col *pCol /* Collection to install */ - ) -{ - SyString *pName = &pCol->sName; - sxu32 iBucket; - /* Hash the collection name */ - pCol->nHash = SyBinHash((const void *)pName->zString,pName->nByte); - /* Install it in the corresponding bucket */ - iBucket = pCol->nHash & (pVm->iColSize - 1); - pCol->pNextCol = pVm->apCol[iBucket]; - if( pVm->apCol[iBucket] ){ - pVm->apCol[iBucket]->pPrevCol = pCol; - } - pVm->apCol[iBucket] = pCol; - /* Link to the list of active collections */ - MACRO_LD_PUSH(pVm->pCol,pCol); - pVm->iCol++; - if( (pVm->iCol >= pVm->iColSize * 4) && pVm->iCol < 10000 ){ - /* Grow the hashtable */ - sxu32 nNewSize = pVm->iColSize << 1; - unqlite_col *pEntry; - unqlite_col **apNew; - sxu32 n; - - apNew = (unqlite_col **)SyMemBackendAlloc(&pVm->sAlloc, nNewSize * sizeof(unqlite_col *)); - if( apNew ){ - /* Zero the new table */ - SyZero((void *)apNew, nNewSize * sizeof(unqlite_col *)); - /* Rehash all entries */ - n = 0; - pEntry = pVm->pCol; - for(;;){ - /* Loop one */ - if( n >= pVm->iCol ){ - break; - } - pEntry->pNextCol = pEntry->pPrevCol = 0; - /* Install in the new bucket */ - iBucket = pEntry->nHash & (nNewSize - 1); - pEntry->pNextCol = apNew[iBucket]; - if( apNew[iBucket] ){ - apNew[iBucket]->pPrevCol = pEntry; - } - apNew[iBucket] = pEntry; - /* Point to the next entry */ - pEntry = pEntry->pNext; - n++; - } - /* Release the old table and reflect the change */ - SyMemBackendFree(&pVm->sAlloc,(void *)pVm->apCol); - pVm->apCol = apNew; - pVm->iColSize = nNewSize; - } - } - return UNQLITE_OK; -} -/* - * Fetch a collection from the target VM. - */ -static unqlite_col * unqliteVmFetchCollection( - unqlite_vm *pVm, /* Target VM */ - SyString *pName /* Lookup name */ - ) -{ - unqlite_col *pCol; - sxu32 nHash; - if( pVm->iCol < 1 ){ - /* Don't bother hashing */ - return 0; - } - nHash = SyBinHash((const void *)pName->zString,pName->nByte); - /* Perform the lookup */ - pCol = pVm->apCol[nHash & ( pVm->iColSize - 1)]; - for(;;){ - if( pCol == 0 ){ - break; - } - if( nHash == pCol->nHash && SyStringCmp(pName,&pCol->sName,SyMemcmp) == 0 ){ - /* Collection found */ - return pCol; - } - /* Point to the next entry */ - pCol = pCol->pNextCol; - } - /* No such collection */ - return 0; -} -/* - * Write and/or alter collection binary header. - */ -static int CollectionSetHeader( - unqlite_kv_engine *pEngine, /* Underlying KV storage engine */ - unqlite_col *pCol, /* Target collection */ - jx9_int64 iRec, /* Last record ID */ - jx9_int64 iTotal, /* Total number of records in this collection */ - jx9_value *pSchema /* Collection schema */ - ) -{ - SyBlob *pHeader = &pCol->sHeader; - unqlite_kv_methods *pMethods; - int iWrite = 0; - int rc; - if( pEngine == 0 ){ - /* Default storage engine */ - pEngine = unqlitePagerGetKvEngine(pCol->pVm->pDb); - } - pMethods = pEngine->pIo->pMethods; - if( SyBlobLength(pHeader) < 1 ){ - Sytm *pCreate = &pCol->sCreation; /* Creation time */ - unqlite_vfs *pVfs; - sxu32 iDos; - /* Magic number */ - rc = SyBlobAppendBig16(pHeader,UNQLITE_COLLECTION_MAGIC); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Initial record ID */ - rc = SyBlobAppendBig64(pHeader,0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Total records in the collection */ - rc = SyBlobAppendBig64(pHeader,0); - if( rc != UNQLITE_OK ){ - return rc; - } - pVfs = (unqlite_vfs *)unqliteExportBuiltinVfs(); - /* Creation time of the collection */ - if( pVfs->xCurrentTime ){ - /* Get the creation time */ - pVfs->xCurrentTime(pVfs,pCreate); - }else{ - /* Zero the structure */ - SyZero(pCreate,sizeof(Sytm)); - } - /* Convert to DOS time */ - SyTimeFormatToDos(pCreate,&iDos); - rc = SyBlobAppendBig32(pHeader,iDos); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Offset to start writing collection schema */ - pCol->nSchemaOfft = SyBlobLength(pHeader); - iWrite = 1; - }else{ - unsigned char *zBinary = (unsigned char *)SyBlobData(pHeader); - /* Header update */ - if( iRec >= 0 ){ - /* Update record ID */ - SyBigEndianPack64(&zBinary[2/* Magic number*/],(sxu64)iRec); - iWrite = 1; - } - if( iTotal >= 0 ){ - /* Total records */ - SyBigEndianPack64(&zBinary[2/* Magic number*/+8/* Record ID*/],(sxu64)iTotal); - iWrite = 1; - } - if( pSchema ){ - /* Collection Schema */ - SyBlobTruncate(pHeader,pCol->nSchemaOfft); - /* Encode the schema to FastJson */ - rc = FastJsonEncode(pSchema,pHeader,0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Copy the collection schema */ - jx9MemObjStore(pSchema,&pCol->sSchema); - iWrite = 1; - } - } - if( iWrite ){ - SyString *pId = &pCol->sName; - /* Reflect the disk and/or in-memory image */ - rc = pMethods->xReplace(pEngine, - (const void *)pId->zString,pId->nByte, - SyBlobData(pHeader),SyBlobLength(pHeader) - ); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Cannot save collection '%z' header in the underlying storage engine", - pId - ); - return rc; - } - } - return UNQLITE_OK; -} -/* - * Load a binary collection from disk. - */ -static int CollectionLoadHeader(unqlite_col *pCol) -{ - SyBlob *pHeader = &pCol->sHeader; - unsigned char *zRaw,*zEnd; - sxu16 nMagic; - sxu32 iDos; - int rc; - SyBlobReset(pHeader); - /* Read the binary header */ - rc = unqlite_kv_cursor_data_callback(pCol->pCursor,unqliteDataConsumer,pHeader); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Perform a sanity check */ - if( SyBlobLength(pHeader) < (2 /* magic */ + 8 /* record_id */ + 8 /* total_records */+ 4 /* DOS creation time*/) ){ - return UNQLITE_CORRUPT; - } - zRaw = (unsigned char *)SyBlobData(pHeader); - zEnd = &zRaw[SyBlobLength(pHeader)]; - /* Extract the magic number */ - SyBigEndianUnpack16(zRaw,&nMagic); - if( nMagic != UNQLITE_COLLECTION_MAGIC ){ - return UNQLITE_CORRUPT; - } - zRaw += 2; /* sizeof(sxu16) */ - /* Extract the record ID */ - SyBigEndianUnpack64(zRaw,(sxu64 *)&pCol->nLastid); - zRaw += 8; /* sizeof(sxu64) */ - /* Total records in the collection */ - SyBigEndianUnpack64(zRaw,(sxu64 *)&pCol->nTotRec); - /* Extract the collection creation date (DOS) */ - zRaw += 8; /* sizeof(sxu64) */ - SyBigEndianUnpack32(zRaw,&iDos); - SyDosTimeFormat(iDos,&pCol->sCreation); - zRaw += 4; - /* Check for a collection schema */ - pCol->nSchemaOfft = (sxu32)(zRaw - (unsigned char *)SyBlobData(pHeader)); - if( zRaw < zEnd ){ - /* Decode the FastJson value */ - FastJsonDecode((const void *)zRaw,(sxu32)(zEnd-zRaw),&pCol->sSchema,0,0); - } - return UNQLITE_OK; -} -/* - * Load or create a binary collection. - */ -static int unqliteVmLoadCollection( - unqlite_vm *pVm, /* Target VM */ - const char *zName, /* Collection name */ - sxu32 nByte, /* zName length */ - int iFlag, /* Control flag */ - unqlite_col **ppOut /* OUT: in-memory collection */ - ) -{ - unqlite_kv_methods *pMethods; - unqlite_kv_engine *pEngine; - unqlite_kv_cursor *pCursor; - unqlite *pDb = pVm->pDb; - unqlite_col *pCol = 0; /* cc warning */ - int rc = SXERR_MEM; - char *zDup = 0; - /* Point to the underlying KV store */ - pEngine = unqlitePagerGetKvEngine(pVm->pDb); - pMethods = pEngine->pIo->pMethods; - /* Allocate a new cursor */ - rc = unqliteInitCursor(pDb,&pCursor); - if( rc != UNQLITE_OK ){ - return rc; - } - if( (iFlag & UNQLITE_VM_COLLECTION_CREATE) == 0 ){ - /* Seek to the desired location */ - rc = pMethods->xSeek(pCursor,(const void *)zName,(int)nByte,UNQLITE_CURSOR_MATCH_EXACT); - if( rc != UNQLITE_OK && (iFlag & UNQLITE_VM_COLLECTION_EXISTS) == 0){ - unqliteGenErrorFormat(pDb,"Collection '%.*s' not defined in the underlying database",nByte,zName); - - unqliteReleaseCursor(pDb,pCursor); - return rc; - } - else if((iFlag & UNQLITE_VM_COLLECTION_EXISTS)){ - unqliteReleaseCursor(pDb,pCursor); - return rc; - } - } - /* Allocate a new instance */ - pCol = (unqlite_col *)SyMemBackendPoolAlloc(&pVm->sAlloc,sizeof(unqlite_col)); - if( pCol == 0 ){ - unqliteGenOutofMem(pDb); - rc = UNQLITE_NOMEM; - goto fail; - } - SyZero(pCol,sizeof(unqlite_col)); - /* Fill in the structure */ - SyBlobInit(&pCol->sWorker,&pVm->sAlloc); - SyBlobInit(&pCol->sHeader,&pVm->sAlloc); - pCol->pVm = pVm; - pCol->pCursor = pCursor; - /* Duplicate collection name */ - zDup = SyMemBackendStrDup(&pVm->sAlloc,zName,nByte); - if( zDup == 0 ){ - unqliteGenOutofMem(pDb); - rc = UNQLITE_NOMEM; - goto fail; - } - pCol->nRecSize = 64; /* Must be a power of two */ - pCol->apRecord = (unqlite_col_record **)SyMemBackendAlloc(&pVm->sAlloc,pCol->nRecSize * sizeof(unqlite_col_record *)); - if( pCol->apRecord == 0 ){ - unqliteGenOutofMem(pDb); - rc = UNQLITE_NOMEM; - goto fail; - } - /* Zero the table */ - SyZero((void *)pCol->apRecord,pCol->nRecSize * sizeof(unqlite_col_record *)); - SyStringInitFromBuf(&pCol->sName,zDup,nByte); - jx9MemObjInit(pVm->pJx9Vm,&pCol->sSchema); - if( iFlag & UNQLITE_VM_COLLECTION_CREATE ){ - /* Create a new collection */ - if( pMethods->xReplace == 0 ){ - /* Read-only KV engine: Generate an error message and return */ - unqliteGenErrorFormat(pDb, - "Cannot create new collection '%z' due to a read-only Key/Value storage engine", - &pCol->sName - ); - rc = UNQLITE_ABORT; /* Abort VM execution */ - goto fail; - } - /* Write the collection header */ - rc = CollectionSetHeader(pEngine,pCol,0,0,0); - if( rc != UNQLITE_OK ){ - rc = UNQLITE_ABORT; /* Abort VM execution */ - goto fail; - } - }else{ - /* Read the collection header */ - rc = CollectionLoadHeader(pCol); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pDb,"Corrupt collection '%z' header",&pCol->sName); - goto fail; - } - } - /* Finally install the collection */ - unqliteVmInstallCollection(pVm,pCol); - /* All done */ - if( ppOut ){ - *ppOut = pCol; - } - return UNQLITE_OK; -fail: - unqliteReleaseCursor(pDb,pCursor); - if( zDup ){ - SyMemBackendFree(&pVm->sAlloc,zDup); - } - if( pCol ){ - if( pCol->apRecord ){ - SyMemBackendFree(&pVm->sAlloc,(void *)pCol->apRecord); - } - SyBlobRelease(&pCol->sHeader); - SyBlobRelease(&pCol->sWorker); - jx9MemObjRelease(&pCol->sSchema); - SyMemBackendPoolFree(&pVm->sAlloc,pCol); - } - return rc; -} -/* - * Fetch a collection. - */ -UNQLITE_PRIVATE unqlite_col * unqliteCollectionFetch( - unqlite_vm *pVm, /* Target VM */ - SyString *pName, /* Lookup key */ - int iFlag /* Control flag */ - ) -{ - unqlite_col *pCol = 0; /* cc warning */ - int rc; - /* Check if the collection is already loaded in memory */ - pCol = unqliteVmFetchCollection(pVm,pName); - if( pCol ){ - /* Already loaded in memory*/ - return pCol; - } - if( (iFlag & UNQLITE_VM_AUTO_LOAD) == 0 ){ - return 0; - } - /* Ask the storage engine for the collection */ - rc = unqliteVmLoadCollection(pVm,pName->zString,pName->nByte,0,&pCol); - /* Return to the caller */ - return rc == UNQLITE_OK ? pCol : 0; -} -/* - * Return the unique ID of the last inserted record. - */ -UNQLITE_PRIVATE jx9_int64 unqliteCollectionLastRecordId(unqlite_col *pCol) -{ - return pCol->nLastid == 0 ? 0 : (pCol->nLastid - 1); -} -/* - * Return the current record ID. - */ -UNQLITE_PRIVATE jx9_int64 unqliteCollectionCurrentRecordId(unqlite_col *pCol) -{ - return pCol->nCurid; -} -/* - * Return the total number of records in a given collection. - */ -UNQLITE_PRIVATE jx9_int64 unqliteCollectionTotalRecords(unqlite_col *pCol) -{ - return pCol->nTotRec; -} -/* - * Reset the record cursor. - */ -UNQLITE_PRIVATE void unqliteCollectionResetRecordCursor(unqlite_col *pCol) -{ - pCol->nCurid = 0; -} -/* - * Fetch a record by its unique ID. - */ -UNQLITE_PRIVATE int unqliteCollectionFetchRecordById( - unqlite_col *pCol, /* Target collection */ - jx9_int64 nId, /* Unique record ID */ - jx9_value *pValue /* OUT: record value */ - ) -{ - SyBlob *pWorker = &pCol->sWorker; - unqlite_col_record *pRec; - int rc; - jx9_value_null(pValue); - /* Perform a cache lookup first */ - pRec = CollectionCacheFetchRecord(pCol,nId); - if( pRec ){ - /* Copy record value */ - jx9MemObjStore(&pRec->sValue,pValue); - return UNQLITE_OK; - } - /* Reset the working buffer */ - SyBlobReset(pWorker); - /* Generate the unique ID */ - SyBlobFormat(pWorker,"%z_%qd",&pCol->sName,nId); - /* Reset the cursor */ - unqlite_kv_cursor_reset(pCol->pCursor); - /* Seek the cursor to the desired location */ - rc = unqlite_kv_cursor_seek(pCol->pCursor, - SyBlobData(pWorker),SyBlobLength(pWorker), - UNQLITE_CURSOR_MATCH_EXACT - ); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Consume the binary JSON */ - SyBlobReset(pWorker); - unqlite_kv_cursor_data_callback(pCol->pCursor,unqliteDataConsumer,pWorker); - if( SyBlobLength(pWorker) < 1 ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Empty record '%qd'",nId - ); - jx9_value_null(pValue); - }else{ - /* Decode the binary JSON */ - rc = FastJsonDecode(SyBlobData(pWorker),SyBlobLength(pWorker),pValue,0,0); - if( rc == UNQLITE_OK ){ - /* Install the record in the cache */ - CollectionCacheInstallRecord(pCol,nId,pValue); - } - } - return rc; -} -/* - * Fetch the next record from a given collection. - */ -UNQLITE_PRIVATE int unqliteCollectionFetchNextRecord(unqlite_col *pCol,jx9_value *pValue) -{ - int rc; - for(;;){ - if( pCol->nCurid >= pCol->nLastid ){ - /* No more records, reset the record cursor ID */ - pCol->nCurid = 0; - /* Return to the caller */ - return SXERR_EOF; - } - rc = unqliteCollectionFetchRecordById(pCol,pCol->nCurid,pValue); - /* Increment the record ID */ - pCol->nCurid++; - /* Lookup result */ - if( rc == UNQLITE_OK || rc != UNQLITE_NOTFOUND ){ - break; - } - } - return rc; -} -/* - * Judge a collection whether exists - */ -UNQLITE_PRIVATE int unqliteExistsCollection( - unqlite_vm *pVm, /* Target VM */ - SyString *pName /* Collection name */ - ) -{ - unqlite_col *pCol; - int rc; - /* Perform a lookup first */ - pCol = unqliteVmFetchCollection(pVm,pName); - if( pCol ){ - /* Already loaded in memory*/ - return UNQLITE_OK; - } - rc = unqliteVmLoadCollection(pVm,pName->zString,pName->nByte,UNQLITE_VM_COLLECTION_EXISTS,0); - return rc; -} -/* - * Create a new collection. - */ -UNQLITE_PRIVATE int unqliteCreateCollection( - unqlite_vm *pVm, /* Target VM */ - SyString *pName /* Collection name */ - ) -{ - unqlite_col *pCol; - int rc; - /* Perform a lookup first */ - pCol = unqliteCollectionFetch(pVm,pName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - return UNQLITE_EXISTS; - } - /* Now, safely create the collection */ - rc = unqliteVmLoadCollection(pVm,pName->zString,pName->nByte,UNQLITE_VM_COLLECTION_CREATE,0); - return rc; -} -/* - * Set a schema (JSON object) for a given collection. - */ -UNQLITE_PRIVATE int unqliteCollectionSetSchema(unqlite_col *pCol,jx9_value *pValue) -{ - int rc; - if( !jx9_value_is_json_object(pValue) ){ - /* Must be a JSON object */ - return SXERR_INVALID; - } - rc = CollectionSetHeader(0,pCol,-1,-1,pValue); - return rc; -} -/* - * Perform a store operation on a given collection. - */ -static int CollectionStore( - unqlite_col *pCol, /* Target collection */ - jx9_value *pValue /* JSON value to be stored */ - ) -{ - SyBlob *pWorker = &pCol->sWorker; - unqlite_kv_methods *pMethods; - unqlite_kv_engine *pEngine; - sxu32 nKeyLen; - int rc; - /* Point to the underlying KV store */ - pEngine = unqlitePagerGetKvEngine(pCol->pVm->pDb); - pMethods = pEngine->pIo->pMethods; - if( pCol->nTotRec >= SXI64_HIGH ){ - /* Collection limit reached. No more records */ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Collection '%z': Records limit reached", - &pCol->sName - ); - return UNQLITE_LIMIT; - } - if( pMethods->xReplace == 0 ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Cannot store record into collection '%z' due to a read-only Key/Value storage engine", - &pCol->sName - ); - return UNQLITE_READ_ONLY; - } - /* Reset the working buffer */ - SyBlobReset(pWorker); - if( jx9_value_is_json_object(pValue) ){ - jx9_value sId; - /* If the given type is a JSON object, then add the special __id field */ - jx9MemObjInitFromInt(pCol->pVm->pJx9Vm,&sId,pCol->nLastid); - jx9_array_add_strkey_elem(pValue,"__id",&sId); - jx9MemObjRelease(&sId); - } - /* Prepare the unique ID for this record */ - SyBlobFormat(pWorker,"%z_%qd",&pCol->sName,pCol->nLastid); - nKeyLen = SyBlobLength(pWorker); - if( nKeyLen < 1 ){ - unqliteGenOutofMem(pCol->pVm->pDb); - return UNQLITE_NOMEM; - } - /* Turn to FastJson */ - rc = FastJsonEncode(pValue,pWorker,0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Finally perform the insertion */ - rc = pMethods->xReplace( - pEngine, - SyBlobData(pWorker),nKeyLen, - SyBlobDataAt(pWorker,nKeyLen),SyBlobLength(pWorker)-nKeyLen - ); - if( rc == UNQLITE_OK ){ - /* Save the value in the cache */ - CollectionCacheInstallRecord(pCol,pCol->nLastid,pValue); - /* Increment the unique __id */ - pCol->nLastid++; - pCol->nTotRec++; - /* Reflect the change */ - rc = CollectionSetHeader(0,pCol,pCol->nLastid,pCol->nTotRec,0); - } - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "IO error while storing record into collection '%z'", - &pCol->sName - ); - return rc; - } - return UNQLITE_OK; -} -/* - * Perform a update operation on a given collection. - */ -static int CollectionUpdate( - unqlite_col *pCol, /* Target collection */ - jx9_int64 nId, /* Record ID */ - jx9_value *pValue /* JSON value to be stored */ -) -{ - SyBlob *pWorker = &pCol->sWorker; - unqlite_kv_methods *pMethods; - unqlite_kv_engine *pEngine; - sxu32 nKeyLen; - int rc; - /* Point to the underlying KV store */ - pEngine = unqlitePagerGetKvEngine(pCol->pVm->pDb); - pMethods = pEngine->pIo->pMethods; - if( pCol->nTotRec >= SXI64_HIGH ){ - /* Collection limit reached. No more records */ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Collection '%z': Records limit reached", - &pCol->sName - ); - return UNQLITE_LIMIT; - } - if( pMethods->xReplace == 0 ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Cannot store record into collection '%z' due to a read-only Key/Value storage engine", - &pCol->sName - ); - return UNQLITE_READ_ONLY; - } - /* Reset the working buffer */ - SyBlobReset(pWorker); - - /* Prepare the unique ID for this record */ - SyBlobFormat(pWorker,"%z_%qd",&pCol->sName, nId); - - /* Reset the cursor */ - unqlite_kv_cursor_reset(pCol->pCursor); - /* Seek the cursor to the desired location */ - rc = unqlite_kv_cursor_seek(pCol->pCursor, - SyBlobData(pWorker),SyBlobLength(pWorker), - UNQLITE_CURSOR_MATCH_EXACT - ); - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "No record to update in collection '%z'", - &pCol->sName - ); - return rc; - } - - if( jx9_value_is_json_object(pValue) ){ - jx9_value sId; - /* If the given type is a JSON object, then add the special __id field */ - jx9MemObjInitFromInt(pCol->pVm->pJx9Vm,&sId,nId); - jx9_array_add_strkey_elem(pValue,"__id",&sId); - jx9MemObjRelease(&sId); - } - - nKeyLen = SyBlobLength(pWorker); - if( nKeyLen < 1 ){ - unqliteGenOutofMem(pCol->pVm->pDb); - return UNQLITE_NOMEM; - } - /* Turn to FastJson */ - rc = FastJsonEncode(pValue,pWorker,0); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Finally perform the insertion */ - rc = pMethods->xReplace( - pEngine, - SyBlobData(pWorker),nKeyLen, - SyBlobDataAt(pWorker,nKeyLen),SyBlobLength(pWorker)-nKeyLen - ); - if( rc == UNQLITE_OK ){ - /* Save the value in the cache */ - CollectionCacheInstallRecord(pCol,nId,pValue); - } - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "IO error while storing record into collection '%z'", - &pCol->sName - ); - return rc; - } - return UNQLITE_OK; -} -/* - * Array walker callback (Refer to jx9_array_walk()). - */ -static int CollectionRecordArrayWalker(jx9_value *pKey,jx9_value *pData,void *pUserData) -{ - unqlite_col *pCol = (unqlite_col *)pUserData; - int rc; - /* Perform the insertion */ - rc = CollectionStore(pCol,pData); - if( rc != UNQLITE_OK ){ - SXUNUSED(pKey); /* cc warning */ - } - return rc; -} -/* - * Perform a store operation on a given collection. - */ -UNQLITE_PRIVATE int unqliteCollectionPut(unqlite_col *pCol,jx9_value *pValue,int iFlag) -{ - int rc; - if( !jx9_value_is_json_object(pValue) && jx9_value_is_json_array(pValue) ){ - /* Iterate over the array and store its members in the collection */ - rc = jx9_array_walk(pValue,CollectionRecordArrayWalker,pCol); - SXUNUSED(iFlag); /* cc warning */ - }else{ - rc = CollectionStore(pCol,pValue); - } - return rc; -} -/* - * Drop a record from a given collection. - */ -UNQLITE_PRIVATE int unqliteCollectionDropRecord( - unqlite_col *pCol, /* Target collection */ - jx9_int64 nId, /* Unique ID of the record to be droped */ - int wr_header, /* True to alter collection header */ - int log_err /* True to log error */ - ) -{ - SyBlob *pWorker = &pCol->sWorker; - int rc; - /* Reset the working buffer */ - SyBlobReset(pWorker); - /* Prepare the unique ID for this record */ - SyBlobFormat(pWorker,"%z_%qd",&pCol->sName,nId); - /* Reset the cursor */ - unqlite_kv_cursor_reset(pCol->pCursor); - /* Seek the cursor to the desired location */ - rc = unqlite_kv_cursor_seek(pCol->pCursor, - SyBlobData(pWorker),SyBlobLength(pWorker), - UNQLITE_CURSOR_MATCH_EXACT - ); - if( rc != UNQLITE_OK ){ - return rc; - } - /* Remove the record from the storage engine */ - rc = unqlite_kv_cursor_delete_entry(pCol->pCursor); - /* Finally, Remove the record from the cache */ - unqliteCollectionCacheRemoveRecord(pCol,nId); - if( rc == UNQLITE_OK ){ - pCol->nTotRec--; - if( wr_header ){ - /* Relect in the collection header */ - rc = CollectionSetHeader(0,pCol,-1,pCol->nTotRec,0); - } - }else if( rc == UNQLITE_NOTIMPLEMENTED ){ - if( log_err ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Cannot delete record from collection '%z' due to a read-only Key/Value storage engine", - &pCol->sName - ); - } - } - return rc; -} -/* - * Update a given record with new data - */ -UNQLITE_PRIVATE int unqliteCollectionUpdateRecord(unqlite_col *pCol,jx9_int64 nId, jx9_value *pValue,int iFlag) -{ - int rc; - if( !jx9_value_is_json_object(pValue) && jx9_value_is_json_array(pValue) ){ - /* Iterate over the array and store its members in the collection */ - rc = jx9_array_walk(pValue,CollectionRecordArrayWalker,pCol); - SXUNUSED(iFlag); /* cc warning */ - }else{ - rc = CollectionUpdate(pCol,nId,pValue); - } - return rc; -} -/* - * Drop a collection from the KV storage engine and the underlying - * unqlite VM. - */ -UNQLITE_PRIVATE int unqliteDropCollection(unqlite_col *pCol) -{ - unqlite_vm *pVm = pCol->pVm; - jx9_int64 nId; - int rc; - /* Reset the cursor */ - unqlite_kv_cursor_reset(pCol->pCursor); - /* Seek the cursor to the desired location */ - rc = unqlite_kv_cursor_seek(pCol->pCursor, - SyStringData(&pCol->sName),SyStringLength(&pCol->sName), - UNQLITE_CURSOR_MATCH_EXACT - ); - if( rc == UNQLITE_OK ){ - /* Remove the record from the storage engine */ - rc = unqlite_kv_cursor_delete_entry(pCol->pCursor); - } - if( rc != UNQLITE_OK ){ - unqliteGenErrorFormat(pCol->pVm->pDb, - "Cannot remove collection '%z' due to a read-only Key/Value storage engine", - &pCol->sName - ); - return rc; - } - /* Drop collection records */ - for( nId = 0 ; nId < pCol->nLastid ; ++nId ){ - unqliteCollectionDropRecord(pCol,nId,0,0); - } - /* Cleanup */ - CollectionCacheRelease(pCol); - SyBlobRelease(&pCol->sHeader); - SyBlobRelease(&pCol->sWorker); - SyMemBackendFree(&pVm->sAlloc,(void *)SyStringData(&pCol->sName)); - unqliteReleaseCursor(pVm->pDb,pCol->pCursor); - /* Unlink */ - if( pCol->pPrevCol ){ - pCol->pPrevCol->pNextCol = pCol->pNextCol; - }else{ - sxu32 iBucket = pCol->nHash & (pVm->iColSize - 1); - pVm->apCol[iBucket] = pCol->pNextCol; - } - if( pCol->pNextCol ){ - pCol->pNextCol->pPrevCol = pCol->pPrevCol; - } - MACRO_LD_REMOVE(pVm->pCol,pCol); - pVm->iCol--; - SyMemBackendPoolFree(&pVm->sAlloc,pCol); - return UNQLITE_OK; -} -/* - * ---------------------------------------------------------- - * File: unqlite_jx9.c - * MD5: 8fddc15b667e85d7b5df5367132518fb - * ---------------------------------------------------------- - */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ - /* $SymiscID: unql_jx9.c v1.2 FreeBSD 2013-01-24 22:45 stable $ */ -#ifndef UNQLITE_AMALGAMATION -#include "unqliteInt.h" -#endif -/* - * This file implements UnQLite functions (db_exists(), db_create(), db_put(), db_get(), etc.) for the - * underlying Jx9 Virtual Machine. - */ -/* - * string db_version(void) - * Return the current version of the unQLite database engine. - * Parameter - * None - * Return - * unQLite version number (string). - */ -static int unqliteBuiltin_db_version(jx9_context *pCtx,int argc,jx9_value **argv) -{ - SXUNUSED(argc); /* cc warning */ - SXUNUSED(argv); - jx9_result_string(pCtx,UNQLITE_VERSION,(int)sizeof(UNQLITE_VERSION)-1); - return JX9_OK; -} -/* - * string db_errlog(void) - * Return the database error log. - * Parameter - * None - * Return - * Database error log (string). - */ -static int unqliteBuiltin_db_errlog(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_vm *pVm; - SyBlob *pErr; - - SXUNUSED(argc); /* cc warning */ - SXUNUSED(argv); - - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Point to the error log */ - pErr = &pVm->pDb->sErr; - /* Return the log */ - jx9_result_string(pCtx,(const char *)SyBlobData(pErr),(int)SyBlobLength(pErr)); - return JX9_OK; -} -/* - * string db_copyright(void) - * string db_credits(void) - * Return the unQLite database engine copyright notice. - * Parameter - * None - * Return - * Copyright notice. - */ -static int unqliteBuiltin_db_credits(jx9_context *pCtx,int argc,jx9_value **argv) -{ - SXUNUSED(argc); /* cc warning */ - SXUNUSED(argv); - jx9_result_string(pCtx,UNQLITE_COPYRIGHT,(int)sizeof(UNQLITE_COPYRIGHT)-1); - return JX9_OK; -} -/* - * string db_sig(void) - * Return the unQLite database engine unique signature. - * Parameter - * None - * Return - * unQLite signature. - */ -static int unqliteBuiltin_db_sig(jx9_context *pCtx,int argc,jx9_value **argv) -{ - SXUNUSED(argc); /* cc warning */ - SXUNUSED(argv); - jx9_result_string(pCtx,UNQLITE_IDENT,sizeof(UNQLITE_IDENT)-1); - return JX9_OK; -} -/* - * bool collection_exists(string $name) - * bool db_exits(string $name) - * Check if a given collection exists in the underlying database. - * Parameter - * name: Lookup name - * Return - * TRUE if the collection exits. FALSE otherwise. - */ -static int unqliteBuiltin_collection_exists(jx9_context *pCtx,int argc,jx9_value **argv) -{ - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Perform the lookup */ - rc = unqliteExistsCollection(pVm, &sName); - /* Lookup result */ - jx9_result_bool(pCtx, rc == UNQLITE_OK ? 1 : 0); - return JX9_OK; -} -/* - * bool collection_create(string $name) - * bool db_create(string $name) - * Create a new collection. - * Parameter - * name: Collection name - * Return - * TRUE if the collection was successfuly created. FALSE otherwise. - */ -static int unqliteBuiltin_collection_create(jx9_context *pCtx,int argc,jx9_value **argv) -{ - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Try to create the collection */ - rc = unqliteCreateCollection(pVm,&sName); - /* Return the result to the caller */ - jx9_result_bool(pCtx,rc == UNQLITE_OK ? 1 : 0); - return JX9_OK; -} -/* - * value db_fetch(string $col_name) - * value db_get(string $col_name) - * Fetch the current record from a given collection and advance - * the record cursor. - * Parameter - * col_name: Collection name - * Return - * Record content success. NULL on failure (No more records to retrieve). - */ -static int unqliteBuiltin_db_fetch_next(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return null */ - jx9_result_null(pCtx); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - /* Fetch the current record */ - jx9_value *pValue; - pValue = jx9_context_new_scalar(pCtx); - if( pValue == 0 ){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Jx9 is running out of memory"); - jx9_result_null(pCtx); - return JX9_OK; - }else{ - rc = unqliteCollectionFetchNextRecord(pCol,pValue); - if( rc == UNQLITE_OK ){ - jx9_result_value(pCtx,pValue); - /* pValue will be automatically released as soon we return from this function */ - }else{ - /* Return null */ - jx9_result_null(pCtx); - } - } - }else{ - /* No such collection, return null */ - jx9_result_null(pCtx); - } - return JX9_OK; -} -/* - * value db_fetch_by_id(string $col_name,int64 $record_id) - * value db_get_by_id(string $col_name,int64 $record_id) - * Fetch a record using its unique ID from a given collection. - * Parameter - * col_name: Collection name - * record_id: Record number (__id field of a JSON object) - * Return - * Record content success. NULL on failure (No such record). - */ -static int unqliteBuiltin_db_fetch_by_id(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - jx9_int64 nId; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 2 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or record ID"); - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - /* Extract the record ID */ - nId = jx9_value_to_int(argv[1]); - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - /* Fetch the desired record */ - jx9_value *pValue; - pValue = jx9_context_new_scalar(pCtx); - if( pValue == 0 ){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Jx9 is running out of memory"); - jx9_result_null(pCtx); - return JX9_OK; - }else{ - rc = unqliteCollectionFetchRecordById(pCol,nId,pValue); - if( rc == UNQLITE_OK ){ - jx9_result_value(pCtx,pValue); - /* pValue will be automatically released as soon we return from this function */ - }else{ - /* No such record, return null */ - jx9_result_null(pCtx); - } - } - }else{ - /* No such collection, return null */ - jx9_result_null(pCtx); - } - return JX9_OK; -} -/* - * array db_fetch_all(string $col_name,[callback filter_callback]) - * array db_get_all(string $col_name,[callback filter_callback]) - * Retrieve all records of a given collection and apply the given - * callback if available to filter records. - * Parameter - * col_name: Collection name - * Return - * Contents of the collection (JSON array) on success. NULL on failure. - */ -static int unqliteBuiltin_db_fetch_all(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return NULL */ - jx9_result_null(pCtx); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - jx9_value *pValue,*pArray,*pCallback = 0; - jx9_value sResult; /* Callback result */ - /* Allocate an empty scalar value and an empty JSON array */ - pArray = jx9_context_new_array(pCtx); - pValue = jx9_context_new_scalar(pCtx); - jx9MemObjInit(pCtx->pVm,&sResult); - if( pValue == 0 || pArray == 0 ){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Jx9 is running out of memory"); - jx9_result_null(pCtx); - return JX9_OK; - } - if( argc > 1 && jx9_value_is_callable(argv[1]) ){ - pCallback = argv[1]; - } - unqliteCollectionResetRecordCursor(pCol); - /* Fetch collection records one after one */ - while( UNQLITE_OK == unqliteCollectionFetchNextRecord(pCol,pValue) ){ - if( pCallback ){ - jx9_value *apArg[2]; - /* Invoke the filter callback */ - apArg[0] = pValue; - rc = jx9VmCallUserFunction(pCtx->pVm,pCallback,1,apArg,&sResult); - if( rc == JX9_OK ){ - int iResult; /* Callback result */ - /* Extract callback result */ - iResult = jx9_value_to_bool(&sResult); - if( !iResult ){ - /* Discard the result */ - unqliteCollectionCacheRemoveRecord(pCol,unqliteCollectionCurrentRecordId(pCol) - 1); - continue; - } - } - } - /* Put the value in the JSON array */ - jx9_array_add_elem(pArray,0,pValue); - /* Release the value */ - jx9_value_null(pValue); - } - jx9MemObjRelease(&sResult); - /* Finally, return our array */ - jx9_result_value(pCtx,pArray); - /* pValue will be automatically released as soon we return from - * this foreign function. - */ - }else{ - /* No such collection, return null */ - jx9_result_null(pCtx); - } - return JX9_OK; -} -/* - * int64 db_last_record_id(string $col_name) - * Return the ID of the last inserted record. - * Parameter - * col_name: Collection name - * Return - * Record ID (64-bit integer) on success. FALSE on failure. - */ -static int unqliteBuiltin_db_last_record_id(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - jx9_result_int64(pCtx,unqliteCollectionLastRecordId(pCol)); - }else{ - /* No such collection, return FALSE */ - jx9_result_bool(pCtx,0); - } - return JX9_OK; -} -/* - * inr64 db_current_record_id(string $col_name) - * Return the current record ID. - * Parameter - * col_name: Collection name - * Return - * Current record ID (64-bit integer) on success. FALSE on failure. - */ -static int unqliteBuiltin_db_current_record_id(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - jx9_result_int64(pCtx,unqliteCollectionCurrentRecordId(pCol)); - }else{ - /* No such collection, return FALSE */ - jx9_result_bool(pCtx,0); - } - return JX9_OK; -} -/* - * bool db_reset_record_cursor(string $col_name) - * Reset the record ID cursor. - * Parameter - * col_name: Collection name - * Return - * TRUE on success. FALSE on failure. - */ -static int unqliteBuiltin_db_reset_record_cursor(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - unqliteCollectionResetRecordCursor(pCol); - jx9_result_bool(pCtx,1); - }else{ - /* No such collection */ - jx9_result_bool(pCtx,0); - } - return JX9_OK; -} -/* - * int64 db_total_records(string $col_name) - * Return the total number of inserted records in the given collection. - * Parameter - * col_name: Collection name - * Return - * Total number of records on success. FALSE on failure. - */ -static int unqliteBuiltin_db_total_records(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - unqlite_int64 nRec; - nRec = unqliteCollectionTotalRecords(pCol); - jx9_result_int64(pCtx,nRec); - }else{ - /* No such collection */ - jx9_result_bool(pCtx,0); - } - return JX9_OK; -} -/* - * string db_creation_date(string $col_name) - * Return the creation date of the given collection. - * Parameter - * col_name: Collection name - * Return - * Creation date on success. FALSE on failure. - */ -static int unqliteBuiltin_db_creation_date(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - Sytm *pTm = &pCol->sCreation; - jx9_result_string_format(pCtx,"%d-%d-%d %02d:%02d:%02d", - pTm->tm_year,pTm->tm_mon,pTm->tm_mday, - pTm->tm_hour,pTm->tm_min,pTm->tm_sec - ); - }else{ - /* No such collection */ - jx9_result_bool(pCtx,0); - } - return JX9_OK; -} -/* - * bool db_store(string $col_name,...) - * bool db_put(string $col_name,...) - * Store one or more JSON values in a given collection. - * Parameter - * col_name: Collection name - * Return - * TRUE on success. FALSE on failure. - */ -static int unqliteBuiltin_db_store(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - int rc; - int i; - /* Extract collection name */ - if( argc < 2 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or records"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol == 0 ){ - jx9_context_throw_error_format(pCtx,JX9_CTX_ERR,"No such collection '%z'",&sName); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - /* Store the given values */ - for( i = 1 ; i < argc ; ++i ){ - rc = unqliteCollectionPut(pCol,argv[i],0); - if( rc != UNQLITE_OK){ - jx9_context_throw_error_format(pCtx,JX9_CTX_ERR, - "Error while storing record %d in collection '%z'",i,&sName - ); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - } - /* All done, return TRUE */ - jx9_result_bool(pCtx,1); - return JX9_OK; -} - -/* - * bool db_update_record(string $col_name, int_64 record_id, object $json_object) - * Update a given record with new json object - * Parameter - * col_name: Collection name - * record_id: ID of the record - * json_object: New Record data - * Return - * TRUE on success. FALSE on failure. - */ -static int unqliteBuiltin_db_update_record(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - jx9_int64 nId; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 2 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or records"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol == 0 ){ - jx9_context_throw_error_format(pCtx,JX9_CTX_ERR,"No such collection '%z'",&sName); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - /* Update a record with the given value */ - nId = jx9_value_to_int64(argv[1]); - rc = unqliteCollectionUpdateRecord(pCol, nId, argv[2], 0); - /* All done, return TRUE */ - jx9_result_bool(pCtx,rc == UNQLITE_OK); - return JX9_OK; -} - -/* - * bool db_drop_collection(string $col_name) - * bool collection_delete(string $col_name) - * Remove a given collection from the database. - * Parameter - * col_name: Collection name - * Return - * TRUE on success. FALSE on failure. - */ -static int unqliteBuiltin_db_drop_col(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol == 0 ){ - jx9_context_throw_error_format(pCtx,JX9_CTX_ERR,"No such collection '%z'",&sName); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - /* Drop the collection */ - rc = unqliteDropCollection(pCol); - /* Processing result */ - jx9_result_bool(pCtx,rc == UNQLITE_OK); - return JX9_OK; -} -/* - * bool db_drop_record(string $col_name,int64 record_id) - * Remove a given record from a collection. - * Parameter - * col_name: Collection name. - * record_id: ID of the record. - * Return - * TRUE on success. FALSE on failure. - */ -static int unqliteBuiltin_db_drop_record(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - jx9_int64 nId; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 2 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or records"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol == 0 ){ - jx9_context_throw_error_format(pCtx,JX9_CTX_ERR,"No such collection '%z'",&sName); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - /* Extract the record ID */ - nId = jx9_value_to_int64(argv[1]); - /* Drop the record */ - rc = unqliteCollectionDropRecord(pCol,nId,1,1); - /* Processing result */ - jx9_result_bool(pCtx,rc == UNQLITE_OK); - return JX9_OK; -} -/* - * bool db_set_schema(string $col_name, object $json_object) - * Set a schema for a given collection. - * Parameter - * col_name: Collection name. - * json_object: Collection schema (Must be a JSON object). - * Return - * TRUE on success. FALSE on failure. - */ -static int unqliteBuiltin_db_set_schema(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - int rc; - /* Extract collection name */ - if( argc < 2 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or db scheme"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - if( !jx9_value_is_json_object(argv[1]) ){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection scheme"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - rc = UNQLITE_NOOP; - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - /* Set the collection scheme */ - rc = unqliteCollectionSetSchema(pCol,argv[1]); - }else{ - jx9_context_throw_error_format(pCtx,JX9_CTX_WARNING, - "No such collection '%z'", - &sName - ); - } - /* Processing result */ - jx9_result_bool(pCtx,rc == UNQLITE_OK); - return JX9_OK; -} -/* - * object db_get_schema(string $col_name) - * Return the schema associated with a given collection. - * Parameter - * col_name: Collection name - * Return - * Collection schema on success. null otherwise. - */ -static int unqliteBuiltin_db_get_schema(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_col *pCol; - const char *zName; - unqlite_vm *pVm; - SyString sName; - int nByte; - /* Extract collection name */ - if( argc < 1 ){ - /* Missing arguments */ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Missing collection name and/or db scheme"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - zName = jx9_value_to_string(argv[0],&nByte); - if( nByte < 1){ - jx9_context_throw_error(pCtx,JX9_CTX_ERR,"Invalid collection name"); - /* Return false */ - jx9_result_bool(pCtx,0); - return JX9_OK; - } - SyStringInitFromBuf(&sName,zName,nByte); - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Fetch the collection */ - pCol = unqliteCollectionFetch(pVm,&sName,UNQLITE_VM_AUTO_LOAD); - if( pCol ){ - /* Return the collection schema */ - jx9_result_value(pCtx,&pCol->sSchema); - }else{ - jx9_context_throw_error_format(pCtx,JX9_CTX_WARNING, - "No such collection '%z'", - &sName - ); - jx9_result_null(pCtx); - } - return JX9_OK; -} -/* - * bool db_begin(void) - * Manually begin a write transaction. - * Parameter - * None - * Return - * TRUE on success. FALSE otherwise. - */ -static int unqliteBuiltin_db_begin(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_vm *pVm; - unqlite *pDb; - int rc; - SXUNUSED(argc); /* cc warning */ - SXUNUSED(argv); - /* Point to the unqlite Vm */ - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Point to the underlying database handle */ - pDb = pVm->pDb; - /* Begin the transaction */ - rc = unqlitePagerBegin(pDb->sDB.pPager); - /* result */ - jx9_result_bool(pCtx,rc == UNQLITE_OK ); - return JX9_OK; -} -/* - * bool db_commit(void) - * Manually commit a transaction. - * Parameter - * None - * Return - * TRUE if the transaction was successfuly commited. FALSE otherwise. - */ -static int unqliteBuiltin_db_commit(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_vm *pVm; - unqlite *pDb; - int rc; - SXUNUSED(argc); /* cc warning */ - SXUNUSED(argv); - /* Point to the unqlite Vm */ - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Point to the underlying database handle */ - pDb = pVm->pDb; - /* Commit the transaction if any */ - rc = unqlitePagerCommit(pDb->sDB.pPager); - /* Commit result */ - jx9_result_bool(pCtx,rc == UNQLITE_OK ); - return JX9_OK; -} -/* - * bool db_rollback(void) - * Manually rollback a transaction. - * Parameter - * None - * Return - * TRUE if the transaction was successfuly rolled back. FALSE otherwise - */ -static int unqliteBuiltin_db_rollback(jx9_context *pCtx,int argc,jx9_value **argv) -{ - unqlite_vm *pVm; - unqlite *pDb; - int rc; - SXUNUSED(argc); /* cc warning */ - SXUNUSED(argv); - /* Point to the unqlite Vm */ - pVm = (unqlite_vm *)jx9_context_user_data(pCtx); - /* Point to the underlying database handle */ - pDb = pVm->pDb; - /* Rollback the transaction if any */ - rc = unqlitePagerRollback(pDb->sDB.pPager,TRUE); - /* Rollback result */ - jx9_result_bool(pCtx,rc == UNQLITE_OK ); - return JX9_OK; -} -/* - * Register all the UnQLite foreign functions defined above. - */ -UNQLITE_PRIVATE int unqliteRegisterJx9Functions(unqlite_vm *pVm) -{ - static const jx9_builtin_func aBuiltin[] = { - { "db_version" , unqliteBuiltin_db_version }, - { "db_copyright", unqliteBuiltin_db_credits }, - { "db_credits" , unqliteBuiltin_db_credits }, - { "db_sig" , unqliteBuiltin_db_sig }, - { "db_errlog", unqliteBuiltin_db_errlog }, - { "collection_exists", unqliteBuiltin_collection_exists }, - { "db_exists", unqliteBuiltin_collection_exists }, - { "collection_create", unqliteBuiltin_collection_create }, - { "db_create", unqliteBuiltin_collection_create }, - { "db_fetch", unqliteBuiltin_db_fetch_next }, - { "db_get", unqliteBuiltin_db_fetch_next }, - { "db_fetch_by_id", unqliteBuiltin_db_fetch_by_id }, - { "db_get_by_id", unqliteBuiltin_db_fetch_by_id }, - { "db_fetch_all", unqliteBuiltin_db_fetch_all }, - { "db_get_all", unqliteBuiltin_db_fetch_all }, - { "db_last_record_id", unqliteBuiltin_db_last_record_id }, - { "db_current_record_id", unqliteBuiltin_db_current_record_id }, - { "db_reset_record_cursor", unqliteBuiltin_db_reset_record_cursor }, - { "db_total_records", unqliteBuiltin_db_total_records }, - { "db_creation_date", unqliteBuiltin_db_creation_date }, - { "db_store", unqliteBuiltin_db_store }, - { "db_update_record", unqliteBuiltin_db_update_record }, - { "db_put", unqliteBuiltin_db_store }, - { "db_drop_collection", unqliteBuiltin_db_drop_col }, - { "collection_delete", unqliteBuiltin_db_drop_col }, - { "db_drop_record", unqliteBuiltin_db_drop_record }, - { "db_set_schema", unqliteBuiltin_db_set_schema }, - { "db_get_schema", unqliteBuiltin_db_get_schema }, - { "db_begin", unqliteBuiltin_db_begin }, - { "db_commit", unqliteBuiltin_db_commit }, - { "db_rollback", unqliteBuiltin_db_rollback }, - }; - int rc = UNQLITE_OK; - sxu32 n; - /* Register the unQLite functions defined above in the Jx9 call table */ - for( n = 0 ; n < SX_ARRAYSIZE(aBuiltin) ; ++n ){ - rc = jx9_create_function(pVm->pJx9Vm,aBuiltin[n].zName,aBuiltin[n].xFunc,pVm); - } - return rc; -} -/* END-OF-IMPLEMENTATION: unqlite@embedded@symisc 34-09-46 */ -/* - * Symisc unQLite: An Embeddable NoSQL (Post Modern) Database Engine. - * Copyright (C) 2012-2013, Symisc Systems http://unqlite.org/ - * Version 1.1.6 - * For information on licensing, redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES - * please contact Symisc Systems via: - * legal@symisc.net - * licensing@symisc.net - * contact@symisc.net - * or visit: - * http://unqlite.org/licensing.html - */ -/* - * Copyright (C) 2012, 2013 Symisc Systems, S.U.A.R.L [M.I.A.G Mrad Chems Eddine ]. - * 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 SYMISC SYSTEMS ``AS IS'' AND ANY EXPRESS - * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR - * NON-INFRINGEMENT, ARE DISCLAIMED. IN NO EVENT SHALL SYMISC SYSTEMS - * 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 _WIN32 -#pragma GCC diagnostic pop -#endif \ No newline at end of file diff --git a/libs/libblade/switchblade/Makefile.am b/libs/libblade/switchblade/Makefile.am deleted file mode 100644 index 312c0b2e47..0000000000 --- a/libs/libblade/switchblade/Makefile.am +++ /dev/null @@ -1,11 +0,0 @@ -AM_CFLAGS += -I$(abs_top_srcdir)/src/include -g -ggdb -O0 -I$(top_srcdir)/../civetweb-1.9.1/include -I$(top_srcdir)/../libks/src/include -TEST_LDADD = $(abs_top_builddir)/libblade.la -L$(top_srcdir)/../civetweb-1.9.1 -L$(top_srcdir)/../libks -lconfig -lm -lpthread -lcivetweb -lks -check_PROGRAMS = - - -check_PROGRAMS += switchblade -switchblade_SOURCES = switchblade.c -switchblade_CFLAGS = $(AM_CFLAGS) -switchblade_LDADD = $(TEST_LDADD) - -sb: $(check_PROGRAMS) diff --git a/libs/libblade/switchblade/restroot/test.lp b/libs/libblade/switchblade/restroot/test.lp deleted file mode 100644 index d3794d07ff..0000000000 --- a/libs/libblade/switchblade/restroot/test.lp +++ /dev/null @@ -1,14 +0,0 @@ -HTTP/1.0 200 OK -Content-Type: text/html - - - -

-Today is: - -

-

-URI is -

- - diff --git a/libs/libblade/switchblade/switchblade.c b/libs/libblade/switchblade/switchblade.c deleted file mode 100644 index 6946ea95c4..0000000000 --- a/libs/libblade/switchblade/switchblade.c +++ /dev/null @@ -1,181 +0,0 @@ -#include "blade.h" - -#define CONSOLE_INPUT_MAX 512 - -// @todo switch to wait condition once something is being done with the main thread during runtime -ks_bool_t g_shutdown = KS_FALSE; - -void loop(blade_handle_t *bh); -void process_console_input(blade_handle_t *bh, char *line); -int rest_service_test(blade_restmgr_t *brestmgr, struct mg_connection *conn, const char **captures); - -typedef void(*command_callback)(blade_handle_t *bh, char *args); - -struct command_def_s { - const char *cmd; - command_callback callback; -}; - -void command_quit(blade_handle_t *bh, char *args); - -static const struct command_def_s command_defs[] = { - { "quit", command_quit }, - - { NULL, NULL } -}; - - -int main(int argc, char **argv) -{ - blade_handle_t *bh = NULL; - config_t config; - config_setting_t *config_blade = NULL; - const char *cfgpath = "switchblade.cfg"; - - ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG); - - blade_init(); - - blade_handle_create(&bh); - - config_init(&config); - if (!config_read_file(&config, cfgpath)) { - ks_log(KS_LOG_ERROR, "%s:%d - %s\n", config_error_file(&config), config_error_line(&config), config_error_text(&config)); - config_destroy(&config); - return EXIT_FAILURE; - } - config_blade = config_lookup(&config, "blade"); - if (!config_blade) { - ks_log(KS_LOG_ERROR, "Missing 'blade' config group\n"); - config_destroy(&config); - return EXIT_FAILURE; - } - if (config_setting_type(config_blade) != CONFIG_TYPE_GROUP) { - ks_log(KS_LOG_ERROR, "The 'blade' config setting is not a group\n"); - return EXIT_FAILURE; - } - - blade_restmgr_service_add(blade_handle_restmgr_get(bh), "GET", "/test/(\\d+)", rest_service_test); - - if (blade_handle_startup(bh, config_blade) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_ERROR, "Blade startup failed\n"); - return EXIT_FAILURE; - } - - loop(bh); - - blade_handle_destroy(&bh); - - config_destroy(&config); - - blade_shutdown(); - - return 0; -} - -void loop(blade_handle_t *bh) -{ - char buf[CONSOLE_INPUT_MAX]; - while (!g_shutdown) { - if (!fgets(buf, CONSOLE_INPUT_MAX, stdin)) break; - - for (int index = 0; buf[index]; ++index) { - if (buf[index] == '\r' || buf[index] == '\n') { - buf[index] = '\0'; - break; - } - } - process_console_input(bh, buf); - - ks_sleep_ms(100); - } -} - -void parse_argument(char **input, char **arg, char terminator) -{ - char *tmp; - - ks_assert(input); - ks_assert(*input); - ks_assert(arg); - - tmp = *input; - *arg = tmp; - - while (*tmp && *tmp != terminator) ++tmp; - if (*tmp == terminator) { - *tmp = '\0'; - ++tmp; - } - *input = tmp; -} - -void process_console_input(blade_handle_t *bh, char *line) -{ - char *args = line; - char *cmd = NULL; - ks_bool_t found = KS_FALSE; - - parse_argument(&args, &cmd, ' '); - - ks_log(KS_LOG_DEBUG, "Command: %s, Args: %s\n", cmd, args); - - for (int32_t index = 0; command_defs[index].cmd; ++index) { - if (!strcmp(command_defs[index].cmd, cmd)) { - found = KS_TRUE; - command_defs[index].callback(bh, args); - } - } - if (!found) ks_log(KS_LOG_INFO, "Command '%s' unknown.\n", cmd); -} - -void command_quit(blade_handle_t *bh, char *args) -{ - //ks_assert(bh); - //ks_assert(args); - - g_shutdown = KS_TRUE; -} - -int rest_service_test(blade_restmgr_t *brestmgr, struct mg_connection *conn, const char **captures) -{ - blade_webrequest_t *request = NULL; - blade_webresponse_t *response = NULL; - cJSON *json = NULL; - cJSON *json_captures = NULL; - //const char *token = NULL; - - blade_webrequest_load(&request, conn); - - // make a json object to send back - json = cJSON_CreateObject(); - cJSON_AddStringToObject(json, "method", blade_webrequest_action_get(request)); - cJSON_AddItemToObject(json, "captures", (json_captures = cJSON_CreateArray())); - for (int i = 0; captures[i]; ++i) cJSON_AddItemToArray(json_captures, cJSON_CreateString(captures[i])); - - blade_webresponse_create(&response, "200"); - blade_webresponse_content_json_append(response, json); - blade_webresponse_send(response, conn); - blade_webresponse_destroy(&response); - - cJSON_Delete(json); - blade_webrequest_destroy(&request); - - //blade_webrequest_oauth2_token_by_credentials_send(KS_FALSE, "192.168.1.99", 80, "/oauth2/token.php", "testclient", "testpass", &token); - // - //ks_pool_free(&token); - - return 200; -} - - -/* For Emacs: -* Local Variables: -* mode:c -* indent-tabs-mode:t -* tab-width:4 -* c-basic-offset:4 -* End: -* For VIM: -* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: -*/ diff --git a/libs/libblade/switchblade/switchblade.cfg b/libs/libblade/switchblade/switchblade.cfg deleted file mode 100644 index 8323480deb..0000000000 --- a/libs/libblade/switchblade/switchblade.cfg +++ /dev/null @@ -1,32 +0,0 @@ -blade: -{ - master: - { - enabled = true; - nodeid = "00000000-0000-0000-0000-000000000000"; - realms = ( "freeswitch" ); - }; - rest: - { - enabled = true; - document_root = "./restroot"; - }; - transport: - { - wss: - { - endpoints: - { - ipv4 = ( { address = "0.0.0.0", port = 2100 } ); - ipv6 = ( { address = "::", port = 2100 } ); - backlog = 128; - ssl: - { - key = "../test/ca/intermediate/private/master@freeswitch-downstream.key.pem"; - cert = "../test/ca/intermediate/certs/master@freeswitch-downstream.cert.pem"; - chain = "../test/ca/intermediate/certs/ca-chain.cert.pem"; - }; - }; - }; - }; -}; diff --git a/libs/libblade/switchblade/switchblade.vcxproj b/libs/libblade/switchblade/switchblade.vcxproj deleted file mode 100644 index d9ae7772db..0000000000 --- a/libs/libblade/switchblade/switchblade.vcxproj +++ /dev/null @@ -1,216 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {8330E669-77F3-4F70-A275-6F7BABE050A7} - Win32Proj - switchblade - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - false - MultiThreadedDebugDLL - - - Console - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;rpcrt4.lib;winmm.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;rpcrt4.lib;winmm.lib;%(AdditionalDependencies) - - - - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - {1a234565-926d-49b2-83e4-d56e0c38c9f2} - - - {a185b162-6cb6-4502-b03f-b56f7699a8d9} - - - {a89d6d18-6203-4149-9051-f8e798e7a3e7} - - - - - - \ No newline at end of file diff --git a/libs/libblade/test/.gitignore b/libs/libblade/test/.gitignore deleted file mode 100644 index 15cd3b9d89..0000000000 --- a/libs/libblade/test/.gitignore +++ /dev/null @@ -1,5 +0,0 @@ -Makefile -Makefile.in -*.log -*.trs -testbuild diff --git a/libs/libblade/test/Makefile.am b/libs/libblade/test/Makefile.am deleted file mode 100644 index 1076cf4349..0000000000 --- a/libs/libblade/test/Makefile.am +++ /dev/null @@ -1,39 +0,0 @@ -AM_CFLAGS += -I$(abs_top_srcdir)/src/include -g -ggdb -O0 -I$(top_srcdir)/../civetweb-1.9.1/include -I$(top_srcdir)/../libks/src/include -TEST_LDADD = $(abs_top_builddir)/libblade.la -L$(top_srcdir)/../civetweb-1.9.1 -L$(top_srcdir)/../libks -lconfig -lm -lpthread -lcivetweb -lks -check_PROGRAMS = - - -check_PROGRAMS += testbuild -testbuild_SOURCES = testbuild.c tap.c -testbuild_CFLAGS = $(AM_CFLAGS) -testbuild_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testcli -testcli_SOURCES = testcli.c tap.c -testcli_CFLAGS = $(AM_CFLAGS) -testcli_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testcon -testcon_SOURCES = testcon.c tap.c -testcon_CFLAGS = $(AM_CFLAGS) -testcon_LDADD = $(TEST_LDADD) - -#check_PROGRAMS += testdht2 -#testdht2_SOURCES = testdht2.c tap.c -#testdht2_CFLAGS = $(AM_CFLAGS) -#testdht2_LDADD = $(TEST_LDADD) - -#check_PROGRAMS += testbuckets -#testbuckets_SOURCES = testbuckets.c tap.c -#testbuckets_CFLAGS = $(AM_CFLAGS) -#testbuckets_LDADD = $(TEST_LDADD) - -#check_PROGRAMS += nodeidgen -#nodeidgen_SOURCES = nodeidgen.c tap.c -#nodeidgen_CFLAGS = $(AM_CFLAGS) -#nodeidgen_LDADD = $(TEST_LDADD) - - -TESTS=$(check_PROGRAMS) - -tests: $(check_PROGRAMS) diff --git a/libs/libblade/test/ca/certs/ca.cert.pem b/libs/libblade/test/ca/certs/ca.cert.pem deleted file mode 100644 index 7dbdbae98f..0000000000 --- a/libs/libblade/test/ca/certs/ca.cert.pem +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFxDCCA6ygAwIBAgIJANi9lXvHAbx4MA0GCSqGSIb3DQEBCwUAMG8xCzAJBgNV -BAYTAlVTMREwDwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzETMBEG -A1UECgwKRnJlZVNXSVRDSDEOMAwGA1UECwwFQmxhZGUxFjAUBgNVBAMMDUJsYWRl -IFJvb3QgQ0EwHhcNMTcwOTA3MDkyNDE2WhcNMjcwOTA1MDkyNDE2WjBvMQswCQYD -VQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xEzAR -BgNVBAoMCkZyZWVTV0lUQ0gxDjAMBgNVBAsMBUJsYWRlMRYwFAYDVQQDDA1CbGFk -ZSBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3Pt3X1j8 -YaRuGb4ENkhfazwZl0K4VlaPhGj4h4wiL5S2Tp8E83HoRkoyQRX0fhKCrHtjNucO -ODkVbf+QMlv1mgEwCq+3SIEA6keBzsUv5sahunfPd+Vgh6+lgp1sAfjFuFlxrRvi -ghO/yHHKE6P2BBgIz3t5QSakE/fLPwejZ98dacyAIxklzLvt4xHRVP7rxfiNFXKR -XHsQd1iaWGSUBNMkUspCl8wO5IAPX75RiFGeA80IjZ518YVjiFBjCdzQfJb9iGJC -GzrOcPJahfum+tzyIO/rIj+ldFyLPY0wbpa0wKeF58HWt52p3HmKnK5FUa7L8RNA -fc3/H+6qyDeBFx92+T6J30q61dcmPayKooUJNsTKslrZ5L2OicWZepa/Oc5dagyz -GEUc+Z11Mgl8/4pT4rUOna29v1d8+StJPN8XgWAHxmwpZ/cY/9GluSq5oB+6PTPc -Q0aFHHUAI97QqfpGOeAWjtVd/3YUcNo82Pa3577rRgh55X+XEySQmBiPWNOsfuCZ -ZvYGOkLmby1SYR/LOwH8opKJyG/bOiZq23aaTPkmEQQSLRzsKxWc2jlE/UllpYX3 -FCu8nFn+L7Tam495IImi8FrpEX16ZpTGhr7YnfbOkMYw+LaRA36U55e5DToJAB5T -CsC2CLhk8QDVoIMPfpYpY4XpdmA4EfDHOG0CAwEAAaNjMGEwHQYDVR0OBBYEFFoz -OX01zWns+ANZ9/6m9g510yWWMB8GA1UdIwQYMBaAFFozOX01zWns+ANZ9/6m9g51 -0yWWMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -CwUAA4ICAQAg74tSgyZKqZtqJPXt/fadZJqWS75cW5TN0rXTKWfzdDXnPfMD2dhZ -h0bH1ZQRamXmXWZni0LpWaOjvqaVNB2TMVStyjEIjLhcBLzR9fhBSXB0BkdVKXvF -Y/pmGN0ZM7BRwbbltgTPYIefftU6BvAyUP5k6y0JJZGy6RTYp7SN2iJ00msqfie/ -zmF83arhFAmW8wjDXMPsSz958+TNgeetFeQjrJ5sbMaApCE21QazHcZw6/zPMRvX -Gr+TPyx/p335MViz5SjeFThQ7XES871pZSbOhmIrugCHO8LJOat3oOlnsc8HkZ/T -AfUjka0SSPA/sRqPxjLWw/OwDn7g5GpbXl7RXpRsKR8CDIRMVrzD71Nk0SOEb3T9 -Dv7UTl6NDYlyYYqx35t/KsiwWjnPtr6Xcl8O9l/tuzf5Tjt1mz9i80BybE9wXHYi -Y3/1SGloKYVXC+HLLrLm1MEldi9GcYZDzxlydAPfHhSHlYWrvOS/J2Dq6uhH7RHn -JV0nE3bVQE01e6iR4BZMYSj4e3BrhMQvkMX67NndYEmoK6+9d77MsK7wblSXja7t -YyXysfQhcudaN/A00CLJt8VNq+h8Q9BR5PFmvIv6/jzV3kmLO4nX9z0CdERyBBUr -cFXfDn2TBpwlLvOQbEWvZPlEh7Vx2hXRRZr97NstLmFLGTdnVdAl9w== ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/index.txt b/libs/libblade/test/ca/index.txt deleted file mode 100644 index 7403eb59d4..0000000000 --- a/libs/libblade/test/ca/index.txt +++ /dev/null @@ -1 +0,0 @@ -V 270905092804Z 1000 unknown /C=US/ST=Illinois/O=FreeSWITCH/OU=Blade/CN=Blade Intermediate CA diff --git a/libs/libblade/test/ca/index.txt.attr b/libs/libblade/test/ca/index.txt.attr deleted file mode 100644 index 8f7e63a347..0000000000 --- a/libs/libblade/test/ca/index.txt.attr +++ /dev/null @@ -1 +0,0 @@ -unique_subject = yes diff --git a/libs/libblade/test/ca/index.txt.old b/libs/libblade/test/ca/index.txt.old deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libblade/test/ca/intermediate/certs/ca-chain.cert.pem b/libs/libblade/test/ca/intermediate/certs/ca-chain.cert.pem deleted file mode 100644 index 36ddebc71d..0000000000 --- a/libs/libblade/test/ca/intermediate/certs/ca-chain.cert.pem +++ /dev/null @@ -1,66 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFtjCCA56gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwbzELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApG -cmVlU1dJVENIMQ4wDAYDVQQLDAVCbGFkZTEWMBQGA1UEAwwNQmxhZGUgUm9vdCBD -QTAeFw0xNzA5MDcwOTI4MDRaFw0yNzA5MDUwOTI4MDRaMGUxCzAJBgNVBAYTAlVT -MREwDwYDVQQIDAhJbGxpbm9pczETMBEGA1UECgwKRnJlZVNXSVRDSDEOMAwGA1UE -CwwFQmxhZGUxHjAcBgNVBAMMFUJsYWRlIEludGVybWVkaWF0ZSBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBALIlY1JmV9z6wjE6iEIXHUl2CRnsa1jD -+uDk4I/OncOdezpfv2mRO9C7VkcefXb5yDrda/qq8r9pNVm6Q2wCJICIlrK9uK90 -SLsB8WsO8Dnrv9E5Tx96U6J5qDx5Ma3IFM7fF1KUP1LVawpS4lMMKFhcyd/P1dAN -ZWlzHCBoM4O9HMo4sKYx4fzxn00yKNK+RU4Wyd3ecntOOg/Dtx3FHt1bExUFuPUW -sgVUR8b+R6Z/1U6iWe+3x/XBAUVCBhyzt7OrCpY0g3TX7wVCh7CafpZnTe54gjMo -1lqSraJ5Dr4Sn1LV1gRa8cVQrNbUZ+m2aHsNLxmpEviHDLTd267x5qXEDCNajesJ -iSALRpQzAJE/neQvVa2fiaV7PbPGlxtUcyR8J9sGfuuby48/RulPQ1CjL1+sI+IE -lnMZqTiab+1TT5OyKMYYRjQ4k3R/gUGn0MhQBcy1VOP6GVGEgeOYACbDSjvYO9HZ -dyM9ivpxLhV3BMVM2B0PmFxLgFdyBlIPkP36/5kBzOFJWdYrMLP/vahFVmTgevDm -8Uhi3PvEt6kKUnWHkBHdajzDKLvbh8y+Ucgap7PtT8apZR+8J9TX87gMFzH5r4Xc -SF97inJ/q098V8dyoPJpL6PRAzigBXGmB2fFhLgtoXfuKfI/nfgQHO7MbYCCFP4z -Och2kFZYehBTAgMBAAGjZjBkMB0GA1UdDgQWBBT24ScXvFFEdGFsK+X5SxmWnAmd -/jAfBgNVHSMEGDAWgBRaMzl9Nc1p7PgDWff+pvYOddMlljASBgNVHRMBAf8ECDAG -AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAgGzDCfJm -weo6oeSFmSLTmlBlTJZO+7igFWf8tunmTkg8wvKe+lCyDd2efNgUocI/NA+X4kRj -YtDH+hq0H+JlDu/p4y4/t6Srx/dh33Ow7eCv2wtuSCeK5Y0euysXhI9gmPquUGOC -HlHkmQcG03NbbrWt0+4IaPAaKxMuV0FR7KArudZvr+8gp9S8o0AkQVFZSbW41HQe -a7DAJmLF0vLQWoVz/YltKjwAMs/ws8OWxUdvcOA3w6XmWmjAFn5hc2MgHgu513c4 -Vbq0535ghU0Eneqc23y2ELa+8hbn5yS5wcK1AS2HG4VoDqOJw+pv4Ko3T33mCR6X -bUABSB+znX5kEZn8KQaP8sLm07kERGjCI3FLPscM1S851tah/iqBgddlIUn/YNpM -9uYQ2PWu6UWvqyZfhgVIlb2LYJNERtKZPeI05SRIbUW93wUTiC6A93fl8SEE7XHa -LMJt6+HLysR2IsXLqlSRZw3rIoT0B3G4uS9Xop89znLAknrOI57OvVAMLaeBrtkl -jepE7RrNX6VcyEY+Ar1p30ax4UJNxjxd3rszIznccerWQzuLo5wYUkuZEfNtnAFB -Z/4qlIn7wkbRevafgmlf/bhP6ZkeJFhqEjOq36Zci5JrnRu3rM/+Vex2ibHVat0E -IZjeGxeofAPEwTaLfPJT7EIWZ+33ZHMcz+8= ------END CERTIFICATE----- ------BEGIN CERTIFICATE----- -MIIFxDCCA6ygAwIBAgIJANi9lXvHAbx4MA0GCSqGSIb3DQEBCwUAMG8xCzAJBgNV -BAYTAlVTMREwDwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzETMBEG -A1UECgwKRnJlZVNXSVRDSDEOMAwGA1UECwwFQmxhZGUxFjAUBgNVBAMMDUJsYWRl -IFJvb3QgQ0EwHhcNMTcwOTA3MDkyNDE2WhcNMjcwOTA1MDkyNDE2WjBvMQswCQYD -VQQGEwJVUzERMA8GA1UECAwISWxsaW5vaXMxEDAOBgNVBAcMB0NoaWNhZ28xEzAR -BgNVBAoMCkZyZWVTV0lUQ0gxDjAMBgNVBAsMBUJsYWRlMRYwFAYDVQQDDA1CbGFk -ZSBSb290IENBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEA3Pt3X1j8 -YaRuGb4ENkhfazwZl0K4VlaPhGj4h4wiL5S2Tp8E83HoRkoyQRX0fhKCrHtjNucO -ODkVbf+QMlv1mgEwCq+3SIEA6keBzsUv5sahunfPd+Vgh6+lgp1sAfjFuFlxrRvi -ghO/yHHKE6P2BBgIz3t5QSakE/fLPwejZ98dacyAIxklzLvt4xHRVP7rxfiNFXKR -XHsQd1iaWGSUBNMkUspCl8wO5IAPX75RiFGeA80IjZ518YVjiFBjCdzQfJb9iGJC -GzrOcPJahfum+tzyIO/rIj+ldFyLPY0wbpa0wKeF58HWt52p3HmKnK5FUa7L8RNA -fc3/H+6qyDeBFx92+T6J30q61dcmPayKooUJNsTKslrZ5L2OicWZepa/Oc5dagyz -GEUc+Z11Mgl8/4pT4rUOna29v1d8+StJPN8XgWAHxmwpZ/cY/9GluSq5oB+6PTPc -Q0aFHHUAI97QqfpGOeAWjtVd/3YUcNo82Pa3577rRgh55X+XEySQmBiPWNOsfuCZ -ZvYGOkLmby1SYR/LOwH8opKJyG/bOiZq23aaTPkmEQQSLRzsKxWc2jlE/UllpYX3 -FCu8nFn+L7Tam495IImi8FrpEX16ZpTGhr7YnfbOkMYw+LaRA36U55e5DToJAB5T -CsC2CLhk8QDVoIMPfpYpY4XpdmA4EfDHOG0CAwEAAaNjMGEwHQYDVR0OBBYEFFoz -OX01zWns+ANZ9/6m9g510yWWMB8GA1UdIwQYMBaAFFozOX01zWns+ANZ9/6m9g51 -0yWWMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgGGMA0GCSqGSIb3DQEB -CwUAA4ICAQAg74tSgyZKqZtqJPXt/fadZJqWS75cW5TN0rXTKWfzdDXnPfMD2dhZ -h0bH1ZQRamXmXWZni0LpWaOjvqaVNB2TMVStyjEIjLhcBLzR9fhBSXB0BkdVKXvF -Y/pmGN0ZM7BRwbbltgTPYIefftU6BvAyUP5k6y0JJZGy6RTYp7SN2iJ00msqfie/ -zmF83arhFAmW8wjDXMPsSz958+TNgeetFeQjrJ5sbMaApCE21QazHcZw6/zPMRvX -Gr+TPyx/p335MViz5SjeFThQ7XES871pZSbOhmIrugCHO8LJOat3oOlnsc8HkZ/T -AfUjka0SSPA/sRqPxjLWw/OwDn7g5GpbXl7RXpRsKR8CDIRMVrzD71Nk0SOEb3T9 -Dv7UTl6NDYlyYYqx35t/KsiwWjnPtr6Xcl8O9l/tuzf5Tjt1mz9i80BybE9wXHYi -Y3/1SGloKYVXC+HLLrLm1MEldi9GcYZDzxlydAPfHhSHlYWrvOS/J2Dq6uhH7RHn -JV0nE3bVQE01e6iR4BZMYSj4e3BrhMQvkMX67NndYEmoK6+9d77MsK7wblSXja7t -YyXysfQhcudaN/A00CLJt8VNq+h8Q9BR5PFmvIv6/jzV3kmLO4nX9z0CdERyBBUr -cFXfDn2TBpwlLvOQbEWvZPlEh7Vx2hXRRZr97NstLmFLGTdnVdAl9w== ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/certs/client@freeswitch-upstream.cert.pem b/libs/libblade/test/ca/intermediate/certs/client@freeswitch-upstream.cert.pem deleted file mode 100644 index b77891973f..0000000000 --- a/libs/libblade/test/ca/intermediate/certs/client@freeswitch-upstream.cert.pem +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFPDCCAySgAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzEyMDgwNloXDTI3MDkwNTEyMDgwNlowdzELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgQ2xpZW50IFVwc3RyZWFt -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7QkR1NA64HPzuYYko7LT -ciwCWu1JLGuA3/7DkskMZ180+sQ3dBG4UjujKMRc0h65oFZc//WYIfmfUznLvLsR -ygghlevPqgGRGdf9WHIMjo9+hLM6MgZ51Eqqydh42L7sen/2bO85gh/pfxno3+uP -FGIJtX6GFiJ5Hp86wF+cqnfRRUFo+0L34+rLY08fITEkTbPjNg5R2jcWa+dWJXIJ -i3pud+ulWPTKalYiUvsqN8tucjJIZb279yzrxsV2qjRqHBCToBj9/kcJHD8gKrpE -f1HsiLLJ7PEAID1fMONTL5sVXCJ1TXpjWNZTlcTCCMAhrEghGMZV0FIm7GS//naq -ywIDAQABo4HjMIHgMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMDMGCWCG -SAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBDbGllbnQgQ2VydGlmaWNhdGUw -HQYDVR0OBBYEFCZDQ3rDX5H3YjuUjV5wsBi/GYyhMB8GA1UdIwQYMBaAFPbhJxe8 -UUR0YWwr5flLGZacCZ3+MA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUEFjAUBggrBgEF -BQcDAgYIKwYBBQUHAwQwHAYDVR0RBBUwE4IRY2xpZW50QGZyZWVzd2l0Y2gwDQYJ -KoZIhvcNAQELBQADggIBAETxSF12VHvtjQA/uP6oUyENmu7wSbINUQZznzyJZSUQ -X0eym9llkUqviMeT9g6wRIoFGSnoMuDkxKbG5k6xVIw6xBUeS+Ce40nhH3qmMkRi -2DZgoqpQHb4DrTszJlXCxLhnnE83DuGDGxN2MbdY1HhCUo8yHqlCiA27hnxk46xh -Xuyx44zoYsdpnROppSwBAeaW9Ewanp7GL8ayWUkbBy0kGV+8wH7u9bpijevmGZSC -iykbYBM7V+RvDvZoywfNSP+l9H77Tv3SI6G40Pfc55M5MbFOa/Po+XjNVeoTOFCu -YIgIm/kA2OUySyBiOy54HfxG5BecZYW+uUm2KIrDX5bS2tZcCww2eo4AKCXEYWrh -1NM1xbeZCregMQ+2gRap4jhB5a49JoH3KPrjFc+1fhnv68bmSAUWwF0twwxev1Aq -ugYwx5lOhAl9+wAZbtsUsmsCp0AmzsIzgv43H6lMXUMjwH8v770J7vpKgMzvXlu8 -wWxFKVMfyocQqvOvBQ3i9SwptnA0ORO8Y8/+Tyu8uW8as/H7z9qaHBcCOWl1RZkR -diBrb5f+OtnamvmDM32APxYtfomj9pgWyxK9vmeCpCILdga3c41iBHbGNJDaNz9q -y9N8z9w887aKQT+HUjoDD2/Zb92Nia1tY+NU0Qd3AQZysJjz1Pq/Eu7KRpHAirTC ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/certs/controller@freeswitch-downstream.cert.pem b/libs/libblade/test/ca/intermediate/certs/controller@freeswitch-downstream.cert.pem deleted file mode 100644 index 2e4878f946..0000000000 --- a/libs/libblade/test/ca/intermediate/certs/controller@freeswitch-downstream.cert.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFmDCCA4CgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzA5NTIxNloXDTI3MDkwNTA5NTIxNlowfTELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEkMCIGA1UEAwwbQmxhZGUgQ29udHJvbGxlciBEb3du -c3RyZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwEA1njlU4qAG -2/KskXthKBI35KDTND92Dqg6gkAvbC/IGEJJyzxw7Fd2AjNMAbNLuaasK9HFRwPh -ZXOLQjvl+wjwtBEAgGw+gLqrLdC3RVuiWlxGsbfB4tAYn9Av44jURYc1Prprnvqz -l8+DIU6UTuRh9JimoyL6NC4rqgcvo8LjR01RNn27RdyeO/VhDjdiU2/vC/OujUqn -InhtGvTB/KrDJtxLEcl15zBGe0PBoolYCF2+8FS2cMFw8y2aeeNeOfvjlzMXOxGG -4vohxUNx/DZh6aNUzbh9Fp7gvJQ8ZRsRNqtI3AgGW4+7Bt4US9ekM8RQjRb51Vk/ -NcFhOKejswIDAQABo4IBODCCATQwCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMC -BkAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2VuZXJhdGVkIFNlcnZlciBDZXJ0 -aWZpY2F0ZTAdBgNVHQ4EFgQUowMxPRDVCvF5Ax/Nvn+quWWny/kwgZoGA1UdIwSB -kjCBj4AU9uEnF7xRRHRhbCvl+UsZlpwJnf6hc6RxMG8xCzAJBgNVBAYTAlVTMREw -DwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzETMBEGA1UECgwKRnJl -ZVNXSVRDSDEOMAwGA1UECwwFQmxhZGUxFjAUBgNVBAMMDUJsYWRlIFJvb3QgQ0GC -AhAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG -9w0BAQsFAAOCAgEAayl96eapLsMHWJDT/p1qfNhMYR+JtO7xaaGLJ+yiibY6T1Be -1R5dLhG7y00Ww1Os9B4F3rWScFxpGqI9GgX8FAGo94Rm3c6+qLAKj/IZmXC6Dgg/ -VzqppcxMt+wo4HsYYhiamVLCyPTrOpPZ82X0+rlR+7iQRbEQ09ubfrb1ec/rDbfU -Kucr1ugwAyOLCmTsK+PAXhAdT/9ci/pL2uO9AxKYgSqvc9VnxoyUusq4Qouxb76I -qmbkGxVN0iP67tJ9jecyaXSoAJ6kBUPAdOesp9shPXmxnU6sPbk5FuJqNU5uZmK+ -KFwGMycLOl8wGAtK88GlupSYHmUT1CDo5rKFtOtyD0wcjM1p+lieQIFYDRV4OLXh -qTa3gtgVRqEcXdn2GdtNFlO87HWR8ptr4gA3jfm/yaC3WGqsgbZtXyPerSIUSd3B -op+5tvE8oqaIahCJV+Lj5XbmXoQkVKGel1xQjZ9rZavBxvwT4BlTNjYBZQHN0wsk -T9Pd1jbytZ9Ffwf3BO/vnkeo4mXSybYN+Ohfh3+bDPMu+NDL7m2/V8ZhIuRCJP0w -YBrlHHxvn4wjVOMix/KXcYXMlVenL0V1xTUHhFhQhBWQ9V4TzzWq/YeZH18MyB/Q -J9vGivKGGFUcs2F7ze+juVOPuUv/hE4ypdPAa4uq+v4HUQAD3mYZkeJnq8o= ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/certs/controller@freeswitch-upstream.cert.pem b/libs/libblade/test/ca/intermediate/certs/controller@freeswitch-upstream.cert.pem deleted file mode 100644 index 3f8d405924..0000000000 --- a/libs/libblade/test/ca/intermediate/certs/controller@freeswitch-upstream.cert.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzA5NTY1MFoXDTI3MDkwNTA5NTY1MFowezELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEiMCAGA1UEAwwZQmxhZGUgQ29udHJvbGxlciBVcHN0 -cmVhbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOLeR7h7lhJR2/T3 -uaG8P20ko4Zo9wudGS/GN+aFv5EpFjlnRRxxbaqc5FFxWSWoJpMvrciX+4izC/jg -mVSU9L7TdK2svGT8rqbXz31H3wEIBP4irKLtW22UbOZL2JoiW8kDUMcyOsc3jTqp -Ewm96PSiYUJHvP6aTJRJdsAlmxZoJu46hxg8tNuy0V6YVPBZFU9NODEosm/wwAFo -Aly70lvUD/kXBZFPBbgMy6xHVPrXKdou2p4IwfWNqm4VmS652YkjG7avSSAnTaph -taTTCvtwOkCvrjJHvg4AG+zgwPdRxSZRqm7+zQdAIyC3zQzQRkbOizlZXej+ffXj -EiPNmNMCAwEAAaOB+TCB9jAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAz -BglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENlcnRpZmlj -YXRlMB0GA1UdDgQWBBSmUpL+sqt/zQFJU1CnvyTAKVEttzAfBgNVHSMEGDAWgBT2 -4ScXvFFEdGFsK+X5SxmWnAmd/jAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYI -KwYBBQUHAwIGCCsGAQUFBwMEMDIGA1UdEQQrMCmCFWNvbnRyb2xsZXJAZnJlZXN3 -aXRjaIIQY29udHJvbGxlckBibGFkZTANBgkqhkiG9w0BAQsFAAOCAgEASJ0KLhWJ -74j+jbHNAKMvqjrhCBSrAr6Ma94L7ut35umYx9jVQhlvW5FQnI+cGU9s+RRm/tkK -bze6aP+FaQdQvQMaxH9P7nCUjEXvKutzATwmXdRNv8MS+i9xVxX1vodZz2nSJ4uE -4GqwiS+HtF5W4DCSId55RQ/1lMsTHsDNi0SspV5nubGJ4qDv/EA6vgkEUMbR6X3J -phLcVTNeM+MvwYFZWZtnXkLnejZUYXMvtCCPwOW3fMQP8lWzNHwCOT+rZCboCnba -NMAOKKkZDiz525wYUsYqDrLN8Q94m1EwgCjIhd9Vn4aLZTBouKAouFW+//L8WWHA -rHFQuw4fy/efZzd1B+AaiM5FfWcKZuGQqa2LJS//GHDQGbRYZZOX505qOSKonSBU -vTLFDYIE4gIYWFFUZqzVOJnafRUGEVl1V5xLZajM7HWMuhCK8p+XA6QM7HQXDUMd -tMa9+EhU5nDF5V+gQmzjNDkh3xGLMbkZceEIP4nSRT9rTEVfILsQ8Q6G9pWYfYf7 -NsSBmax/F/8Jbx2gw9UVo7HVDx6dA5FRht4K8qiT6aA/5pRSOADMRz6ISM2idiF9 -NjadbBo+nVPtKosSF5ZGKxTAdYMUb34FMdp1N7J4UzG1ZBiLpNa3+7R3GGbtlNy5 -WLn35rnLEHYt9KvftBeYz58KVaiPQz/af8c= ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/certs/intermediate.cert.pem b/libs/libblade/test/ca/intermediate/certs/intermediate.cert.pem deleted file mode 100644 index 8e915f4784..0000000000 --- a/libs/libblade/test/ca/intermediate/certs/intermediate.cert.pem +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFtjCCA56gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwbzELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApG -cmVlU1dJVENIMQ4wDAYDVQQLDAVCbGFkZTEWMBQGA1UEAwwNQmxhZGUgUm9vdCBD -QTAeFw0xNzA5MDcwOTI4MDRaFw0yNzA5MDUwOTI4MDRaMGUxCzAJBgNVBAYTAlVT -MREwDwYDVQQIDAhJbGxpbm9pczETMBEGA1UECgwKRnJlZVNXSVRDSDEOMAwGA1UE -CwwFQmxhZGUxHjAcBgNVBAMMFUJsYWRlIEludGVybWVkaWF0ZSBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBALIlY1JmV9z6wjE6iEIXHUl2CRnsa1jD -+uDk4I/OncOdezpfv2mRO9C7VkcefXb5yDrda/qq8r9pNVm6Q2wCJICIlrK9uK90 -SLsB8WsO8Dnrv9E5Tx96U6J5qDx5Ma3IFM7fF1KUP1LVawpS4lMMKFhcyd/P1dAN -ZWlzHCBoM4O9HMo4sKYx4fzxn00yKNK+RU4Wyd3ecntOOg/Dtx3FHt1bExUFuPUW -sgVUR8b+R6Z/1U6iWe+3x/XBAUVCBhyzt7OrCpY0g3TX7wVCh7CafpZnTe54gjMo -1lqSraJ5Dr4Sn1LV1gRa8cVQrNbUZ+m2aHsNLxmpEviHDLTd267x5qXEDCNajesJ -iSALRpQzAJE/neQvVa2fiaV7PbPGlxtUcyR8J9sGfuuby48/RulPQ1CjL1+sI+IE -lnMZqTiab+1TT5OyKMYYRjQ4k3R/gUGn0MhQBcy1VOP6GVGEgeOYACbDSjvYO9HZ -dyM9ivpxLhV3BMVM2B0PmFxLgFdyBlIPkP36/5kBzOFJWdYrMLP/vahFVmTgevDm -8Uhi3PvEt6kKUnWHkBHdajzDKLvbh8y+Ucgap7PtT8apZR+8J9TX87gMFzH5r4Xc -SF97inJ/q098V8dyoPJpL6PRAzigBXGmB2fFhLgtoXfuKfI/nfgQHO7MbYCCFP4z -Och2kFZYehBTAgMBAAGjZjBkMB0GA1UdDgQWBBT24ScXvFFEdGFsK+X5SxmWnAmd -/jAfBgNVHSMEGDAWgBRaMzl9Nc1p7PgDWff+pvYOddMlljASBgNVHRMBAf8ECDAG -AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAgGzDCfJm -weo6oeSFmSLTmlBlTJZO+7igFWf8tunmTkg8wvKe+lCyDd2efNgUocI/NA+X4kRj -YtDH+hq0H+JlDu/p4y4/t6Srx/dh33Ow7eCv2wtuSCeK5Y0euysXhI9gmPquUGOC -HlHkmQcG03NbbrWt0+4IaPAaKxMuV0FR7KArudZvr+8gp9S8o0AkQVFZSbW41HQe -a7DAJmLF0vLQWoVz/YltKjwAMs/ws8OWxUdvcOA3w6XmWmjAFn5hc2MgHgu513c4 -Vbq0535ghU0Eneqc23y2ELa+8hbn5yS5wcK1AS2HG4VoDqOJw+pv4Ko3T33mCR6X -bUABSB+znX5kEZn8KQaP8sLm07kERGjCI3FLPscM1S851tah/iqBgddlIUn/YNpM -9uYQ2PWu6UWvqyZfhgVIlb2LYJNERtKZPeI05SRIbUW93wUTiC6A93fl8SEE7XHa -LMJt6+HLysR2IsXLqlSRZw3rIoT0B3G4uS9Xop89znLAknrOI57OvVAMLaeBrtkl -jepE7RrNX6VcyEY+Ar1p30ax4UJNxjxd3rszIznccerWQzuLo5wYUkuZEfNtnAFB -Z/4qlIn7wkbRevafgmlf/bhP6ZkeJFhqEjOq36Zci5JrnRu3rM/+Vex2ibHVat0E -IZjeGxeofAPEwTaLfPJT7EIWZ+33ZHMcz+8= ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/certs/master@freeswitch-downstream.cert.pem b/libs/libblade/test/ca/intermediate/certs/master@freeswitch-downstream.cert.pem deleted file mode 100644 index 2e0a69d061..0000000000 --- a/libs/libblade/test/ca/intermediate/certs/master@freeswitch-downstream.cert.pem +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzA5NDQ1OVoXDTI3MDkwNTA5NDQ1OVoweTELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEgMB4GA1UEAwwXQmxhZGUgTWFzdGVyIERvd25zdHJl -YW0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK8mciD1y9F1fz08+4 -V1d6VZfv87h0V4/JihsjFEAlvog1W1BsfMPw1eNGmykDVZPVgmmgjP95UZYBm9gW -P26ze6hzA/7wpqdCs/tG0XsiCS5NsyP/9g33hcXJqzhTQXoqn0cGRJzrre2AfPoX -2CijWpjH3ufUMyZzN7fP7/VCYNEDR/4Geyp3RjBnqw4PlFqroME2762kNC5jGkCh -hPUpYrKwNE6mvQ6H0DwjJl9cHR9ynssU81h0TDa98N6kKcDLzK7BAoFtFGRKrFkL -db8LtvbG6zyLZrpJtwkcgfyOoKtXMuHGfISnnMtbgi6IyZPfo/9RcKK6q6a3/ZHE -plwJAgMBAAGjggFkMIIBYDAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDAz -BglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmlj -YXRlMB0GA1UdDgQWBBT5po36vCPKHCecbSz1ueDbFDZ1jjCBmgYDVR0jBIGSMIGP -gBT24ScXvFFEdGFsK+X5SxmWnAmd/qFzpHEwbzELMAkGA1UEBhMCVVMxETAPBgNV -BAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJ -VENIMQ4wDAYDVQQLDAVCbGFkZTEWMBQGA1UEAwwNQmxhZGUgUm9vdCBDQYICEAAw -DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMCoGA1UdEQQjMCGC -EW1hc3RlckBmcmVlc3dpdGNoggxtYXN0ZXJAYmxhZGUwDQYJKoZIhvcNAQELBQAD -ggIBAJ73CuGQvtFkzQxhVvmWcg7TOHeV6I1IycBXDgyEdL3MEC+z2vXpz7NwzcnD -F0gYBVXAszSkNsLxmzUsxSr2IOy6rTJ/5R/GP9/3NLfjF1H2r1lxytfngMokp6ts -AiCPu5fiIyYPlwj3Gcbw0+n8LL06oPKGf291eHRjWlJbbI0grUW2W1Mdajd9U42z -vadoY0NAtWiZI3sM+OpicAg8hsYLN40KsnEag3Y6JdsDNiT05qKDhUcqVROlVcu4 -CT4u1gNROClAt/iUGA2s8jsPutPEedtGuAcIHqDk60C6D0v1+PokdFGG2ZBgHZLg -fXRsPYzAtsqhyUW3jyR3XYEoIj1tU+zHRZT7B5wPczhOBk5LOHf+QYVVzwV3Ff5x -8de8KRXRSg2ygLQGpBWTqMzzrjVgeSBNzC5nW/WaQHkMxmSGvUyvpUVUX/ySpDFf -r4JfpYHmxSNWVdRVBmCzTBq2qM8npaPWsagXWOv/hdZcrTTi6nnrWxSIFogiY9DX -YW2GUENt56AlXlyhiKd/NCWkQN5c/pRjV8EVUSTNuLNwFsGWmdZdjiaOUeILxHQS -OyzvTgKohqHikECl1wISRuDY8Fbu+xfqUaERsSfS35CBKW3qtmnmg+9meE6MRj7I -sbWoHXx7dJZst7vcDDsBptUPNUFKsgHKqfaGrb7hJGro/vTV ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/cnf/client@freeswitch-upstream.cnf b/libs/libblade/test/ca/intermediate/cnf/client@freeswitch-upstream.cnf deleted file mode 100644 index c6c37bfca8..0000000000 --- a/libs/libblade/test/ca/intermediate/cnf/client@freeswitch-upstream.cnf +++ /dev/null @@ -1,133 +0,0 @@ -# OpenSSL intermediate CA configuration file. -# Copy to `/root/ca/intermediate/openssl.cnf`. - -[ ca ] -# `man ca` -default_ca = CA_default - -[ CA_default ] -# Directory and file locations. -dir = . -certs = $dir/certs -crl_dir = $dir/crl -new_certs_dir = $dir/newcerts -database = $dir/index.txt -serial = $dir/serial -RANDFILE = $dir/private/.rand - -# The root key and root certificate. -private_key = $dir/private/intermediate.key.pem -certificate = $dir/certs/intermediate.cert.pem - -# For certificate revocation lists. -crlnumber = $dir/crlnumber -crl = $dir/crl/intermediate.crl.pem -crl_extensions = crl_ext -default_crl_days = 30 - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -name_opt = ca_default -cert_opt = ca_default -default_days = 375 -preserve = no -policy = policy_loose - -[ policy_strict ] -# The root CA should only sign intermediate certificates that match. -# See the POLICY FORMAT section of `man ca`. -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ policy_loose ] -# Allow the intermediate CA to sign a more diverse range of certificates. -# See the POLICY FORMAT section of the `ca` man page. -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ req ] -# Options for the `req` tool (`man req`). -default_bits = 2048 -distinguished_name = req_distinguished_name -string_mask = utf8only - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -# Extension to add when the -x509 option is used. -x509_extensions = v3_ca - -[ req_distinguished_name ] -# See . -countryName = Country Name (2 letter code) -stateOrProvinceName = State or Province Name -localityName = Locality Name -0.organizationName = Organization Name -organizationalUnitName = Organizational Unit Name -commonName = Common Name -emailAddress = Email Address - -# Optionally, specify some defaults. -countryName_default = US -stateOrProvinceName_default = Illinois -localityName_default = Chicago -0.organizationName_default = FreeSWITCH -organizationalUnitName_default = Blade -emailAddress_default = - -[ v3_ca ] -# Extensions for a typical CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ v3_intermediate_ca ] -# Extensions for a typical intermediate CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true, pathlen:0 -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ usr_cert ] -# Extensions for client certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = client, email -nsComment = "OpenSSL Generated Client Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment -extendedKeyUsage = clientAuth, emailProtection -subjectAltName = DNS: client@freeswitch - -[ server_cert ] -# Extensions for server certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = server -nsComment = "OpenSSL Generated Server Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer:always -keyUsage = critical, digitalSignature, keyEncipherment -extendedKeyUsage = serverAuth - -[ crl_ext ] -# Extension for CRLs (`man x509v3_config`). -authorityKeyIdentifier=keyid:always - -[ ocsp ] -# Extension for OCSP signing certificates (`man ocsp`). -basicConstraints = CA:FALSE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, digitalSignature -extendedKeyUsage = critical, OCSPSigning \ No newline at end of file diff --git a/libs/libblade/test/ca/intermediate/cnf/controller@freeswitch-upstream.cnf b/libs/libblade/test/ca/intermediate/cnf/controller@freeswitch-upstream.cnf deleted file mode 100644 index 6f7c702fc2..0000000000 --- a/libs/libblade/test/ca/intermediate/cnf/controller@freeswitch-upstream.cnf +++ /dev/null @@ -1,133 +0,0 @@ -# OpenSSL intermediate CA configuration file. -# Copy to `/root/ca/intermediate/openssl.cnf`. - -[ ca ] -# `man ca` -default_ca = CA_default - -[ CA_default ] -# Directory and file locations. -dir = . -certs = $dir/certs -crl_dir = $dir/crl -new_certs_dir = $dir/newcerts -database = $dir/index.txt -serial = $dir/serial -RANDFILE = $dir/private/.rand - -# The root key and root certificate. -private_key = $dir/private/intermediate.key.pem -certificate = $dir/certs/intermediate.cert.pem - -# For certificate revocation lists. -crlnumber = $dir/crlnumber -crl = $dir/crl/intermediate.crl.pem -crl_extensions = crl_ext -default_crl_days = 30 - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -name_opt = ca_default -cert_opt = ca_default -default_days = 375 -preserve = no -policy = policy_loose - -[ policy_strict ] -# The root CA should only sign intermediate certificates that match. -# See the POLICY FORMAT section of `man ca`. -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ policy_loose ] -# Allow the intermediate CA to sign a more diverse range of certificates. -# See the POLICY FORMAT section of the `ca` man page. -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ req ] -# Options for the `req` tool (`man req`). -default_bits = 2048 -distinguished_name = req_distinguished_name -string_mask = utf8only - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -# Extension to add when the -x509 option is used. -x509_extensions = v3_ca - -[ req_distinguished_name ] -# See . -countryName = Country Name (2 letter code) -stateOrProvinceName = State or Province Name -localityName = Locality Name -0.organizationName = Organization Name -organizationalUnitName = Organizational Unit Name -commonName = Common Name -emailAddress = Email Address - -# Optionally, specify some defaults. -countryName_default = US -stateOrProvinceName_default = Illinois -localityName_default = Chicago -0.organizationName_default = FreeSWITCH -organizationalUnitName_default = Blade -emailAddress_default = - -[ v3_ca ] -# Extensions for a typical CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ v3_intermediate_ca ] -# Extensions for a typical intermediate CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true, pathlen:0 -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ usr_cert ] -# Extensions for client certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = client, email -nsComment = "OpenSSL Generated Client Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment -extendedKeyUsage = clientAuth, emailProtection -subjectAltName = DNS: controller@freeswitch, DNS: controller@blade - -[ server_cert ] -# Extensions for server certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = server -nsComment = "OpenSSL Generated Server Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer:always -keyUsage = critical, digitalSignature, keyEncipherment -extendedKeyUsage = serverAuth - -[ crl_ext ] -# Extension for CRLs (`man x509v3_config`). -authorityKeyIdentifier=keyid:always - -[ ocsp ] -# Extension for OCSP signing certificates (`man ocsp`). -basicConstraints = CA:FALSE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, digitalSignature -extendedKeyUsage = critical, OCSPSigning \ No newline at end of file diff --git a/libs/libblade/test/ca/intermediate/cnf/master@freeswitch-downstream.cnf b/libs/libblade/test/ca/intermediate/cnf/master@freeswitch-downstream.cnf deleted file mode 100644 index f23e7c91e1..0000000000 --- a/libs/libblade/test/ca/intermediate/cnf/master@freeswitch-downstream.cnf +++ /dev/null @@ -1,133 +0,0 @@ -# OpenSSL intermediate CA configuration file. -# Copy to `/root/ca/intermediate/openssl.cnf`. - -[ ca ] -# `man ca` -default_ca = CA_default - -[ CA_default ] -# Directory and file locations. -dir = . -certs = $dir/certs -crl_dir = $dir/crl -new_certs_dir = $dir/newcerts -database = $dir/index.txt -serial = $dir/serial -RANDFILE = $dir/private/.rand - -# The root key and root certificate. -private_key = $dir/private/intermediate.key.pem -certificate = $dir/certs/intermediate.cert.pem - -# For certificate revocation lists. -crlnumber = $dir/crlnumber -crl = $dir/crl/intermediate.crl.pem -crl_extensions = crl_ext -default_crl_days = 30 - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -name_opt = ca_default -cert_opt = ca_default -default_days = 375 -preserve = no -policy = policy_loose - -[ policy_strict ] -# The root CA should only sign intermediate certificates that match. -# See the POLICY FORMAT section of `man ca`. -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ policy_loose ] -# Allow the intermediate CA to sign a more diverse range of certificates. -# See the POLICY FORMAT section of the `ca` man page. -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ req ] -# Options for the `req` tool (`man req`). -default_bits = 2048 -distinguished_name = req_distinguished_name -string_mask = utf8only - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -# Extension to add when the -x509 option is used. -x509_extensions = v3_ca - -[ req_distinguished_name ] -# See . -countryName = Country Name (2 letter code) -stateOrProvinceName = State or Province Name -localityName = Locality Name -0.organizationName = Organization Name -organizationalUnitName = Organizational Unit Name -commonName = Common Name -emailAddress = Email Address - -# Optionally, specify some defaults. -countryName_default = US -stateOrProvinceName_default = Illinois -localityName_default = Chicago -0.organizationName_default = FreeSWITCH -organizationalUnitName_default = Blade -emailAddress_default = - -[ v3_ca ] -# Extensions for a typical CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ v3_intermediate_ca ] -# Extensions for a typical intermediate CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true, pathlen:0 -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ usr_cert ] -# Extensions for client certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = client, email -nsComment = "OpenSSL Generated Client Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment -extendedKeyUsage = clientAuth, emailProtection - -[ server_cert ] -# Extensions for server certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = server -nsComment = "OpenSSL Generated Server Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer:always -keyUsage = critical, digitalSignature, keyEncipherment -extendedKeyUsage = serverAuth -subjectAltName = DNS: master@freeswitch, DNS: master@blade - -[ crl_ext ] -# Extension for CRLs (`man x509v3_config`). -authorityKeyIdentifier=keyid:always - -[ ocsp ] -# Extension for OCSP signing certificates (`man ocsp`). -basicConstraints = CA:FALSE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, digitalSignature -extendedKeyUsage = critical, OCSPSigning \ No newline at end of file diff --git a/libs/libblade/test/ca/intermediate/crlnumber b/libs/libblade/test/ca/intermediate/crlnumber deleted file mode 100644 index e37d32abba..0000000000 --- a/libs/libblade/test/ca/intermediate/crlnumber +++ /dev/null @@ -1 +0,0 @@ -1000 \ No newline at end of file diff --git a/libs/libblade/test/ca/intermediate/csr/client@freeswitch-upstream.csr.pem b/libs/libblade/test/ca/intermediate/csr/client@freeswitch-upstream.csr.pem deleted file mode 100644 index f39fb3c5d0..0000000000 --- a/libs/libblade/test/ca/intermediate/csr/client@freeswitch-upstream.csr.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICvDCCAaQCAQAwdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw -DgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQLDAVC -bGFkZTEeMBwGA1UEAwwVQmxhZGUgQ2xpZW50IFVwc3RyZWFtMIIBIjANBgkqhkiG -9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7QkR1NA64HPzuYYko7LTciwCWu1JLGuA3/7D -kskMZ180+sQ3dBG4UjujKMRc0h65oFZc//WYIfmfUznLvLsRygghlevPqgGRGdf9 -WHIMjo9+hLM6MgZ51Eqqydh42L7sen/2bO85gh/pfxno3+uPFGIJtX6GFiJ5Hp86 -wF+cqnfRRUFo+0L34+rLY08fITEkTbPjNg5R2jcWa+dWJXIJi3pud+ulWPTKalYi -UvsqN8tucjJIZb279yzrxsV2qjRqHBCToBj9/kcJHD8gKrpEf1HsiLLJ7PEAID1f -MONTL5sVXCJ1TXpjWNZTlcTCCMAhrEghGMZV0FIm7GS//naqywIDAQABoAAwDQYJ -KoZIhvcNAQELBQADggEBAJd+fNwHr5soFlNbWb5kMP5utXwJhElEfnQ25puC0jhP -I03z63MS8Chi1Uaxo9MBpFnC84LVmhPT+7RwpRBubVJEWq2WUjZRvbt5dih+kGum -zC7dDhHAMx8Gk8TwsYnnzCDkcvetCCTfrn5otYlVxc/36PWoMB4dL426XSi5JVx0 -nxeXmbiIpZP9udwXDl6J6i8HhjtGpveiVIV3RrfleApYHAxFa5pVP9l3pwMt9RqX -+TbqXexAXrJoVoi8JENjDMGl2H/95UaXB7W/6iIHc/1hy3ebk5OCahxeIoS8LHgX -LsLKJDVsz5eOmfo5rF7lT1WVgp2TTS+W6ys2uX3j/cY= ------END CERTIFICATE REQUEST----- diff --git a/libs/libblade/test/ca/intermediate/csr/controller@freeswitch-downstream.csr.pem b/libs/libblade/test/ca/intermediate/csr/controller@freeswitch-downstream.csr.pem deleted file mode 100644 index d143bb913f..0000000000 --- a/libs/libblade/test/ca/intermediate/csr/controller@freeswitch-downstream.csr.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICwjCCAaoCAQAwfTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw -DgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQLDAVC -bGFkZTEkMCIGA1UEAwwbQmxhZGUgQ29udHJvbGxlciBEb3duc3RyZWFtMIIBIjAN -BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwEA1njlU4qAG2/KskXthKBI35KDT -ND92Dqg6gkAvbC/IGEJJyzxw7Fd2AjNMAbNLuaasK9HFRwPhZXOLQjvl+wjwtBEA -gGw+gLqrLdC3RVuiWlxGsbfB4tAYn9Av44jURYc1Prprnvqzl8+DIU6UTuRh9Jim -oyL6NC4rqgcvo8LjR01RNn27RdyeO/VhDjdiU2/vC/OujUqnInhtGvTB/KrDJtxL -Ecl15zBGe0PBoolYCF2+8FS2cMFw8y2aeeNeOfvjlzMXOxGG4vohxUNx/DZh6aNU -zbh9Fp7gvJQ8ZRsRNqtI3AgGW4+7Bt4US9ekM8RQjRb51Vk/NcFhOKejswIDAQAB -oAAwDQYJKoZIhvcNAQELBQADggEBAHvlM/HiAI9fO2QlQRX4lAo0Y+pLYZDI0kjY -2PWsLEzI69mBYLTGFrvzYaSzwDUzkHBuypV69BTsWHQBbnMfRRvvqXQCObYcnMUa -IDaM4m4YLSYICWUYe+aCQZIMjg13TRspR8H1DlbRUlYFvsYumMeaeAauHW0t6xfL -H5vaFtNs0G4apJpb++CoCW/2cWS5Iyj4oViGitX1ajl4oRBzjPMqRQFlqUWExcM8 -a/XA1STOcIw8qlIWZw9hL7StOoMcAFhybjadZIGLYSI8Y1vCl2+Ur+bRNEU0VY4h -k9jhjr09pI0rHcXhXziZ88NRIQL4rT04MJnjR2G7AY18bKIGnqk= ------END CERTIFICATE REQUEST----- diff --git a/libs/libblade/test/ca/intermediate/csr/controller@freeswitch-upstream.csr.pem b/libs/libblade/test/ca/intermediate/csr/controller@freeswitch-upstream.csr.pem deleted file mode 100644 index 9704b1280e..0000000000 --- a/libs/libblade/test/ca/intermediate/csr/controller@freeswitch-upstream.csr.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICwDCCAagCAQAwezELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw -DgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQLDAVC -bGFkZTEiMCAGA1UEAwwZQmxhZGUgQ29udHJvbGxlciBVcHN0cmVhbTCCASIwDQYJ -KoZIhvcNAQEBBQADggEPADCCAQoCggEBAOLeR7h7lhJR2/T3uaG8P20ko4Zo9wud -GS/GN+aFv5EpFjlnRRxxbaqc5FFxWSWoJpMvrciX+4izC/jgmVSU9L7TdK2svGT8 -rqbXz31H3wEIBP4irKLtW22UbOZL2JoiW8kDUMcyOsc3jTqpEwm96PSiYUJHvP6a -TJRJdsAlmxZoJu46hxg8tNuy0V6YVPBZFU9NODEosm/wwAFoAly70lvUD/kXBZFP -BbgMy6xHVPrXKdou2p4IwfWNqm4VmS652YkjG7avSSAnTaphtaTTCvtwOkCvrjJH -vg4AG+zgwPdRxSZRqm7+zQdAIyC3zQzQRkbOizlZXej+ffXjEiPNmNMCAwEAAaAA -MA0GCSqGSIb3DQEBCwUAA4IBAQDTJmaPVFGJ7lgj2TOJi66WSLkXUc3wKCX7dkX/ -GIGXyr2hsabYT3FOkWlL0W/CI2KXkFEItnHPE4Plit9E+O/fZYGWjfSHhVUa6rzF -w+rM2EWklAl6s/zH1/MoliRG68aluyqv8aIyovRNfAj3F3FaDW5qiIaSVtp3Znlu -OlrIQD3ixqIa4na0+kr9MEV+wehDl5Uib0j8GLf7dM/drEywzWVkjaPRttrgvu/M -loill3Ta13RQMs0qzu1zx36mbb+hyahq5kyrabWDisV6cmWxbcSCIGCOCfgHdXMl -KYupqGBp1ey7KEl3erB4WQ8Rhl7z01+5QEhd875pNmHRE5/w ------END CERTIFICATE REQUEST----- diff --git a/libs/libblade/test/ca/intermediate/csr/intermediate.csr.pem b/libs/libblade/test/ca/intermediate/csr/intermediate.csr.pem deleted file mode 100644 index 900701b01a..0000000000 --- a/libs/libblade/test/ca/intermediate/csr/intermediate.csr.pem +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIIEvDCCAqQCAQAwdzELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw -DgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQLDAVC -bGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMIICIjANBgkqhkiG -9w0BAQEFAAOCAg8AMIICCgKCAgEAsiVjUmZX3PrCMTqIQhcdSXYJGexrWMP64OTg -j86dw517Ol+/aZE70LtWRx59dvnIOt1r+qryv2k1WbpDbAIkgIiWsr24r3RIuwHx -aw7wOeu/0TlPH3pTonmoPHkxrcgUzt8XUpQ/UtVrClLiUwwoWFzJ38/V0A1laXMc -IGgzg70cyjiwpjHh/PGfTTIo0r5FThbJ3d5ye046D8O3HcUe3VsTFQW49RayBVRH -xv5Hpn/VTqJZ77fH9cEBRUIGHLO3s6sKljSDdNfvBUKHsJp+lmdN7niCMyjWWpKt -onkOvhKfUtXWBFrxxVCs1tRn6bZoew0vGakS+IcMtN3brvHmpcQMI1qN6wmJIAtG -lDMAkT+d5C9VrZ+JpXs9s8aXG1RzJHwn2wZ+65vLjz9G6U9DUKMvX6wj4gSWcxmp -OJpv7VNPk7IoxhhGNDiTdH+BQafQyFAFzLVU4/oZUYSB45gAJsNKO9g70dl3Iz2K -+nEuFXcExUzYHQ+YXEuAV3IGUg+Q/fr/mQHM4UlZ1isws/+9qEVWZOB68ObxSGLc -+8S3qQpSdYeQEd1qPMMou9uHzL5RyBqns+1PxqllH7wn1NfzuAwXMfmvhdxIX3uK -cn+rT3xXx3Kg8mkvo9EDOKAFcaYHZ8WEuC2hd+4p8j+d+BAc7sxtgIIU/jM5yHaQ -Vlh6EFMCAwEAAaAAMA0GCSqGSIb3DQEBCwUAA4ICAQBjDnbyUJMn5Av78pt611u3 -/QrYxH1SHEwjtSwPcusmoTCNhMIF07GLlRuLNB1teyNLFtLzq345d/sr+o9BmFAS -ODpW0rN5RGXnZKvHPrBARFRb/UdyZDlvbl/ksVT6b9fzroPRtU3IqgdAXvKnvJ7G -1RCaIxyZd7T856Z7Eq2tmn0AblyXJLWy2JpBy6CzRK4KFCuNHbs+HrVBXeHD6Tgc -pcbtIKohHw/x3r+OX2uf6hr0bfewePE7y5pf4yVb+eaN6TMQQHHSN+oIVSNi8yKk -Sr1wd8F5OEp6teYKj4Nlrc8giOkrIV91a1XUJsKgYfzpT4GevIw+8U1uIa8qB3Ow -ZchgdsltZAFR0MGmwJNKGQ6JAmFmZTGD2G43P3Y9EnXDiGYWo5k0UkdghaoJIIAO -DYxGhEGOINjHmJyQik0ha+38+cLAWoItrSIShZaHDMSXx5ujaFBrZxPa662BwkF4 -zUXmAW09ww64owAYZ+a1EuujTcLDYszSzIbF6UqBoCeDpq3L5wEgFzl0zktVIwWI -YQ99IKOj0JVbsIbikFoteXFbE1x0dR05Mgx9NaCDrIlmmydnsNW5xvwQISYnr92U -HgS0/xfgaPo8hqDpl6rjlfwj0Ay/LZTAfH/xGjN69DZbTgf55PRhkTdwMLiQuY6e -ENqjprP7sJ7aYdND59jAmQ== ------END CERTIFICATE REQUEST----- diff --git a/libs/libblade/test/ca/intermediate/csr/master@freeswitch-downstream.csr.pem b/libs/libblade/test/ca/intermediate/csr/master@freeswitch-downstream.csr.pem deleted file mode 100644 index e8922958b8..0000000000 --- a/libs/libblade/test/ca/intermediate/csr/master@freeswitch-downstream.csr.pem +++ /dev/null @@ -1,17 +0,0 @@ ------BEGIN CERTIFICATE REQUEST----- -MIICvjCCAaYCAQAweTELMAkGA1UEBhMCVVMxETAPBgNVBAgMCElsbGlub2lzMRAw -DgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQLDAVC -bGFkZTEgMB4GA1UEAwwXQmxhZGUgTWFzdGVyIERvd25zdHJlYW0wggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK8mciD1y9F1fz08+4V1d6VZfv87h0V4/J -ihsjFEAlvog1W1BsfMPw1eNGmykDVZPVgmmgjP95UZYBm9gWP26ze6hzA/7wpqdC -s/tG0XsiCS5NsyP/9g33hcXJqzhTQXoqn0cGRJzrre2AfPoX2CijWpjH3ufUMyZz -N7fP7/VCYNEDR/4Geyp3RjBnqw4PlFqroME2762kNC5jGkChhPUpYrKwNE6mvQ6H -0DwjJl9cHR9ynssU81h0TDa98N6kKcDLzK7BAoFtFGRKrFkLdb8LtvbG6zyLZrpJ -twkcgfyOoKtXMuHGfISnnMtbgi6IyZPfo/9RcKK6q6a3/ZHEplwJAgMBAAGgADAN -BgkqhkiG9w0BAQsFAAOCAQEAGJ9T9wIQ5i8X8bkvsNKJMWBWWx6O5ihP77ve6Pet -BHvfJyV++lFbaU4Af/5R5eE5aOXpfIzMm6MHmvE3sSSL9+Bkaqw+VL1jKieG919C -+5CEC1T053QWjbqYG7dp5wVTMJ3MSawvsrkD6sr2rSHhu2pcmEeF5bFcaaYSXVsG -vmCGQh7lUj8N79xdiuQvYUM1Lpgo/81WeUWXjCaMVkv6Hdzp0Hx9avCSweb6kklE -dSUjOkOKGA/+IoCXmFiLxNs0hzxrkG85aVCmv1x5fcm9mqNVoqBY2YqWWguavDnz -DT88l92ZDGqJpVmB+a5H1pC9JY54UUyii462ZMcDmrMK7g== ------END CERTIFICATE REQUEST----- diff --git a/libs/libblade/test/ca/intermediate/index.txt b/libs/libblade/test/ca/intermediate/index.txt deleted file mode 100644 index b4cb5e3ca0..0000000000 --- a/libs/libblade/test/ca/intermediate/index.txt +++ /dev/null @@ -1,4 +0,0 @@ -V 270905094459Z 1000 unknown /C=US/ST=Illinois/L=Chicago/O=FreeSWITCH/OU=Blade/CN=Blade Master Downstream -V 270905095216Z 1001 unknown /C=US/ST=Illinois/L=Chicago/O=FreeSWITCH/OU=Blade/CN=Blade Controller Downstream -V 270905095650Z 1002 unknown /C=US/ST=Illinois/L=Chicago/O=FreeSWITCH/OU=Blade/CN=Blade Controller Upstream -V 270905120806Z 1003 unknown /C=US/ST=Illinois/L=Chicago/O=FreeSWITCH/OU=Blade/CN=Blade Client Upstream diff --git a/libs/libblade/test/ca/intermediate/index.txt.attr b/libs/libblade/test/ca/intermediate/index.txt.attr deleted file mode 100644 index 8f7e63a347..0000000000 --- a/libs/libblade/test/ca/intermediate/index.txt.attr +++ /dev/null @@ -1 +0,0 @@ -unique_subject = yes diff --git a/libs/libblade/test/ca/intermediate/index.txt.attr.old b/libs/libblade/test/ca/intermediate/index.txt.attr.old deleted file mode 100644 index 8f7e63a347..0000000000 --- a/libs/libblade/test/ca/intermediate/index.txt.attr.old +++ /dev/null @@ -1 +0,0 @@ -unique_subject = yes diff --git a/libs/libblade/test/ca/intermediate/index.txt.old b/libs/libblade/test/ca/intermediate/index.txt.old deleted file mode 100644 index 47a2db0ebf..0000000000 --- a/libs/libblade/test/ca/intermediate/index.txt.old +++ /dev/null @@ -1,3 +0,0 @@ -V 270905094459Z 1000 unknown /C=US/ST=Illinois/L=Chicago/O=FreeSWITCH/OU=Blade/CN=Blade Master Downstream -V 270905095216Z 1001 unknown /C=US/ST=Illinois/L=Chicago/O=FreeSWITCH/OU=Blade/CN=Blade Controller Downstream -V 270905095650Z 1002 unknown /C=US/ST=Illinois/L=Chicago/O=FreeSWITCH/OU=Blade/CN=Blade Controller Upstream diff --git a/libs/libblade/test/ca/intermediate/newcerts/1000.pem b/libs/libblade/test/ca/intermediate/newcerts/1000.pem deleted file mode 100644 index 2e0a69d061..0000000000 --- a/libs/libblade/test/ca/intermediate/newcerts/1000.pem +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFwDCCA6igAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzA5NDQ1OVoXDTI3MDkwNTA5NDQ1OVoweTELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEgMB4GA1UEAwwXQmxhZGUgTWFzdGVyIERvd25zdHJl -YW0wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDK8mciD1y9F1fz08+4 -V1d6VZfv87h0V4/JihsjFEAlvog1W1BsfMPw1eNGmykDVZPVgmmgjP95UZYBm9gW -P26ze6hzA/7wpqdCs/tG0XsiCS5NsyP/9g33hcXJqzhTQXoqn0cGRJzrre2AfPoX -2CijWpjH3ufUMyZzN7fP7/VCYNEDR/4Geyp3RjBnqw4PlFqroME2762kNC5jGkCh -hPUpYrKwNE6mvQ6H0DwjJl9cHR9ynssU81h0TDa98N6kKcDLzK7BAoFtFGRKrFkL -db8LtvbG6zyLZrpJtwkcgfyOoKtXMuHGfISnnMtbgi6IyZPfo/9RcKK6q6a3/ZHE -plwJAgMBAAGjggFkMIIBYDAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIGQDAz -BglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgU2VydmVyIENlcnRpZmlj -YXRlMB0GA1UdDgQWBBT5po36vCPKHCecbSz1ueDbFDZ1jjCBmgYDVR0jBIGSMIGP -gBT24ScXvFFEdGFsK+X5SxmWnAmd/qFzpHEwbzELMAkGA1UEBhMCVVMxETAPBgNV -BAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJ -VENIMQ4wDAYDVQQLDAVCbGFkZTEWMBQGA1UEAwwNQmxhZGUgUm9vdCBDQYICEAAw -DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMCoGA1UdEQQjMCGC -EW1hc3RlckBmcmVlc3dpdGNoggxtYXN0ZXJAYmxhZGUwDQYJKoZIhvcNAQELBQAD -ggIBAJ73CuGQvtFkzQxhVvmWcg7TOHeV6I1IycBXDgyEdL3MEC+z2vXpz7NwzcnD -F0gYBVXAszSkNsLxmzUsxSr2IOy6rTJ/5R/GP9/3NLfjF1H2r1lxytfngMokp6ts -AiCPu5fiIyYPlwj3Gcbw0+n8LL06oPKGf291eHRjWlJbbI0grUW2W1Mdajd9U42z -vadoY0NAtWiZI3sM+OpicAg8hsYLN40KsnEag3Y6JdsDNiT05qKDhUcqVROlVcu4 -CT4u1gNROClAt/iUGA2s8jsPutPEedtGuAcIHqDk60C6D0v1+PokdFGG2ZBgHZLg -fXRsPYzAtsqhyUW3jyR3XYEoIj1tU+zHRZT7B5wPczhOBk5LOHf+QYVVzwV3Ff5x -8de8KRXRSg2ygLQGpBWTqMzzrjVgeSBNzC5nW/WaQHkMxmSGvUyvpUVUX/ySpDFf -r4JfpYHmxSNWVdRVBmCzTBq2qM8npaPWsagXWOv/hdZcrTTi6nnrWxSIFogiY9DX -YW2GUENt56AlXlyhiKd/NCWkQN5c/pRjV8EVUSTNuLNwFsGWmdZdjiaOUeILxHQS -OyzvTgKohqHikECl1wISRuDY8Fbu+xfqUaERsSfS35CBKW3qtmnmg+9meE6MRj7I -sbWoHXx7dJZst7vcDDsBptUPNUFKsgHKqfaGrb7hJGro/vTV ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/newcerts/1001.pem b/libs/libblade/test/ca/intermediate/newcerts/1001.pem deleted file mode 100644 index 2e4878f946..0000000000 --- a/libs/libblade/test/ca/intermediate/newcerts/1001.pem +++ /dev/null @@ -1,32 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFmDCCA4CgAwIBAgICEAEwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzA5NTIxNloXDTI3MDkwNTA5NTIxNlowfTELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEkMCIGA1UEAwwbQmxhZGUgQ29udHJvbGxlciBEb3du -c3RyZWFtMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwEA1njlU4qAG -2/KskXthKBI35KDTND92Dqg6gkAvbC/IGEJJyzxw7Fd2AjNMAbNLuaasK9HFRwPh -ZXOLQjvl+wjwtBEAgGw+gLqrLdC3RVuiWlxGsbfB4tAYn9Av44jURYc1Prprnvqz -l8+DIU6UTuRh9JimoyL6NC4rqgcvo8LjR01RNn27RdyeO/VhDjdiU2/vC/OujUqn -InhtGvTB/KrDJtxLEcl15zBGe0PBoolYCF2+8FS2cMFw8y2aeeNeOfvjlzMXOxGG -4vohxUNx/DZh6aNUzbh9Fp7gvJQ8ZRsRNqtI3AgGW4+7Bt4US9ekM8RQjRb51Vk/ -NcFhOKejswIDAQABo4IBODCCATQwCQYDVR0TBAIwADARBglghkgBhvhCAQEEBAMC -BkAwMwYJYIZIAYb4QgENBCYWJE9wZW5TU0wgR2VuZXJhdGVkIFNlcnZlciBDZXJ0 -aWZpY2F0ZTAdBgNVHQ4EFgQUowMxPRDVCvF5Ax/Nvn+quWWny/kwgZoGA1UdIwSB -kjCBj4AU9uEnF7xRRHRhbCvl+UsZlpwJnf6hc6RxMG8xCzAJBgNVBAYTAlVTMREw -DwYDVQQIDAhJbGxpbm9pczEQMA4GA1UEBwwHQ2hpY2FnbzETMBEGA1UECgwKRnJl -ZVNXSVRDSDEOMAwGA1UECwwFQmxhZGUxFjAUBgNVBAMMDUJsYWRlIFJvb3QgQ0GC -AhAAMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUEDDAKBggrBgEFBQcDATANBgkqhkiG -9w0BAQsFAAOCAgEAayl96eapLsMHWJDT/p1qfNhMYR+JtO7xaaGLJ+yiibY6T1Be -1R5dLhG7y00Ww1Os9B4F3rWScFxpGqI9GgX8FAGo94Rm3c6+qLAKj/IZmXC6Dgg/ -VzqppcxMt+wo4HsYYhiamVLCyPTrOpPZ82X0+rlR+7iQRbEQ09ubfrb1ec/rDbfU -Kucr1ugwAyOLCmTsK+PAXhAdT/9ci/pL2uO9AxKYgSqvc9VnxoyUusq4Qouxb76I -qmbkGxVN0iP67tJ9jecyaXSoAJ6kBUPAdOesp9shPXmxnU6sPbk5FuJqNU5uZmK+ -KFwGMycLOl8wGAtK88GlupSYHmUT1CDo5rKFtOtyD0wcjM1p+lieQIFYDRV4OLXh -qTa3gtgVRqEcXdn2GdtNFlO87HWR8ptr4gA3jfm/yaC3WGqsgbZtXyPerSIUSd3B -op+5tvE8oqaIahCJV+Lj5XbmXoQkVKGel1xQjZ9rZavBxvwT4BlTNjYBZQHN0wsk -T9Pd1jbytZ9Ffwf3BO/vnkeo4mXSybYN+Ohfh3+bDPMu+NDL7m2/V8ZhIuRCJP0w -YBrlHHxvn4wjVOMix/KXcYXMlVenL0V1xTUHhFhQhBWQ9V4TzzWq/YeZH18MyB/Q -J9vGivKGGFUcs2F7ze+juVOPuUv/hE4ypdPAa4uq+v4HUQAD3mYZkeJnq8o= ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/newcerts/1002.pem b/libs/libblade/test/ca/intermediate/newcerts/1002.pem deleted file mode 100644 index 3f8d405924..0000000000 --- a/libs/libblade/test/ca/intermediate/newcerts/1002.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFVjCCAz6gAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzA5NTY1MFoXDTI3MDkwNTA5NTY1MFowezELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEiMCAGA1UEAwwZQmxhZGUgQ29udHJvbGxlciBVcHN0 -cmVhbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOLeR7h7lhJR2/T3 -uaG8P20ko4Zo9wudGS/GN+aFv5EpFjlnRRxxbaqc5FFxWSWoJpMvrciX+4izC/jg -mVSU9L7TdK2svGT8rqbXz31H3wEIBP4irKLtW22UbOZL2JoiW8kDUMcyOsc3jTqp -Ewm96PSiYUJHvP6aTJRJdsAlmxZoJu46hxg8tNuy0V6YVPBZFU9NODEosm/wwAFo -Aly70lvUD/kXBZFPBbgMy6xHVPrXKdou2p4IwfWNqm4VmS652YkjG7avSSAnTaph -taTTCvtwOkCvrjJHvg4AG+zgwPdRxSZRqm7+zQdAIyC3zQzQRkbOizlZXej+ffXj -EiPNmNMCAwEAAaOB+TCB9jAJBgNVHRMEAjAAMBEGCWCGSAGG+EIBAQQEAwIFoDAz -BglghkgBhvhCAQ0EJhYkT3BlblNTTCBHZW5lcmF0ZWQgQ2xpZW50IENlcnRpZmlj -YXRlMB0GA1UdDgQWBBSmUpL+sqt/zQFJU1CnvyTAKVEttzAfBgNVHSMEGDAWgBT2 -4ScXvFFEdGFsK+X5SxmWnAmd/jAOBgNVHQ8BAf8EBAMCBeAwHQYDVR0lBBYwFAYI -KwYBBQUHAwIGCCsGAQUFBwMEMDIGA1UdEQQrMCmCFWNvbnRyb2xsZXJAZnJlZXN3 -aXRjaIIQY29udHJvbGxlckBibGFkZTANBgkqhkiG9w0BAQsFAAOCAgEASJ0KLhWJ -74j+jbHNAKMvqjrhCBSrAr6Ma94L7ut35umYx9jVQhlvW5FQnI+cGU9s+RRm/tkK -bze6aP+FaQdQvQMaxH9P7nCUjEXvKutzATwmXdRNv8MS+i9xVxX1vodZz2nSJ4uE -4GqwiS+HtF5W4DCSId55RQ/1lMsTHsDNi0SspV5nubGJ4qDv/EA6vgkEUMbR6X3J -phLcVTNeM+MvwYFZWZtnXkLnejZUYXMvtCCPwOW3fMQP8lWzNHwCOT+rZCboCnba -NMAOKKkZDiz525wYUsYqDrLN8Q94m1EwgCjIhd9Vn4aLZTBouKAouFW+//L8WWHA -rHFQuw4fy/efZzd1B+AaiM5FfWcKZuGQqa2LJS//GHDQGbRYZZOX505qOSKonSBU -vTLFDYIE4gIYWFFUZqzVOJnafRUGEVl1V5xLZajM7HWMuhCK8p+XA6QM7HQXDUMd -tMa9+EhU5nDF5V+gQmzjNDkh3xGLMbkZceEIP4nSRT9rTEVfILsQ8Q6G9pWYfYf7 -NsSBmax/F/8Jbx2gw9UVo7HVDx6dA5FRht4K8qiT6aA/5pRSOADMRz6ISM2idiF9 -NjadbBo+nVPtKosSF5ZGKxTAdYMUb34FMdp1N7J4UzG1ZBiLpNa3+7R3GGbtlNy5 -WLn35rnLEHYt9KvftBeYz58KVaiPQz/af8c= ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/newcerts/1003.pem b/libs/libblade/test/ca/intermediate/newcerts/1003.pem deleted file mode 100644 index b77891973f..0000000000 --- a/libs/libblade/test/ca/intermediate/newcerts/1003.pem +++ /dev/null @@ -1,30 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFPDCCAySgAwIBAgICEAMwDQYJKoZIhvcNAQELBQAwZTELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRMwEQYDVQQKDApGcmVlU1dJVENIMQ4wDAYDVQQL -DAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgSW50ZXJtZWRpYXRlIENBMB4XDTE3MDkw -NzEyMDgwNloXDTI3MDkwNTEyMDgwNlowdzELMAkGA1UEBhMCVVMxETAPBgNVBAgM -CElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApGcmVlU1dJVENI -MQ4wDAYDVQQLDAVCbGFkZTEeMBwGA1UEAwwVQmxhZGUgQ2xpZW50IFVwc3RyZWFt -MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7QkR1NA64HPzuYYko7LT -ciwCWu1JLGuA3/7DkskMZ180+sQ3dBG4UjujKMRc0h65oFZc//WYIfmfUznLvLsR -ygghlevPqgGRGdf9WHIMjo9+hLM6MgZ51Eqqydh42L7sen/2bO85gh/pfxno3+uP -FGIJtX6GFiJ5Hp86wF+cqnfRRUFo+0L34+rLY08fITEkTbPjNg5R2jcWa+dWJXIJ -i3pud+ulWPTKalYiUvsqN8tucjJIZb279yzrxsV2qjRqHBCToBj9/kcJHD8gKrpE -f1HsiLLJ7PEAID1fMONTL5sVXCJ1TXpjWNZTlcTCCMAhrEghGMZV0FIm7GS//naq -ywIDAQABo4HjMIHgMAkGA1UdEwQCMAAwEQYJYIZIAYb4QgEBBAQDAgWgMDMGCWCG -SAGG+EIBDQQmFiRPcGVuU1NMIEdlbmVyYXRlZCBDbGllbnQgQ2VydGlmaWNhdGUw -HQYDVR0OBBYEFCZDQ3rDX5H3YjuUjV5wsBi/GYyhMB8GA1UdIwQYMBaAFPbhJxe8 -UUR0YWwr5flLGZacCZ3+MA4GA1UdDwEB/wQEAwIF4DAdBgNVHSUEFjAUBggrBgEF -BQcDAgYIKwYBBQUHAwQwHAYDVR0RBBUwE4IRY2xpZW50QGZyZWVzd2l0Y2gwDQYJ -KoZIhvcNAQELBQADggIBAETxSF12VHvtjQA/uP6oUyENmu7wSbINUQZznzyJZSUQ -X0eym9llkUqviMeT9g6wRIoFGSnoMuDkxKbG5k6xVIw6xBUeS+Ce40nhH3qmMkRi -2DZgoqpQHb4DrTszJlXCxLhnnE83DuGDGxN2MbdY1HhCUo8yHqlCiA27hnxk46xh -Xuyx44zoYsdpnROppSwBAeaW9Ewanp7GL8ayWUkbBy0kGV+8wH7u9bpijevmGZSC -iykbYBM7V+RvDvZoywfNSP+l9H77Tv3SI6G40Pfc55M5MbFOa/Po+XjNVeoTOFCu -YIgIm/kA2OUySyBiOy54HfxG5BecZYW+uUm2KIrDX5bS2tZcCww2eo4AKCXEYWrh -1NM1xbeZCregMQ+2gRap4jhB5a49JoH3KPrjFc+1fhnv68bmSAUWwF0twwxev1Aq -ugYwx5lOhAl9+wAZbtsUsmsCp0AmzsIzgv43H6lMXUMjwH8v770J7vpKgMzvXlu8 -wWxFKVMfyocQqvOvBQ3i9SwptnA0ORO8Y8/+Tyu8uW8as/H7z9qaHBcCOWl1RZkR -diBrb5f+OtnamvmDM32APxYtfomj9pgWyxK9vmeCpCILdga3c41iBHbGNJDaNz9q -y9N8z9w887aKQT+HUjoDD2/Zb92Nia1tY+NU0Qd3AQZysJjz1Pq/Eu7KRpHAirTC ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/intermediate/openssl.cnf b/libs/libblade/test/ca/intermediate/openssl.cnf deleted file mode 100644 index 2a0e3561f0..0000000000 --- a/libs/libblade/test/ca/intermediate/openssl.cnf +++ /dev/null @@ -1,132 +0,0 @@ -# OpenSSL intermediate CA configuration file. -# Copy to `/root/ca/intermediate/openssl.cnf`. - -[ ca ] -# `man ca` -default_ca = CA_default - -[ CA_default ] -# Directory and file locations. -dir = . -certs = $dir/certs -crl_dir = $dir/crl -new_certs_dir = $dir/newcerts -database = $dir/index.txt -serial = $dir/serial -RANDFILE = $dir/private/.rand - -# The root key and root certificate. -private_key = $dir/private/intermediate.key.pem -certificate = $dir/certs/intermediate.cert.pem - -# For certificate revocation lists. -crlnumber = $dir/crlnumber -crl = $dir/crl/intermediate.crl.pem -crl_extensions = crl_ext -default_crl_days = 30 - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -name_opt = ca_default -cert_opt = ca_default -default_days = 375 -preserve = no -policy = policy_loose - -[ policy_strict ] -# The root CA should only sign intermediate certificates that match. -# See the POLICY FORMAT section of `man ca`. -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ policy_loose ] -# Allow the intermediate CA to sign a more diverse range of certificates. -# See the POLICY FORMAT section of the `ca` man page. -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ req ] -# Options for the `req` tool (`man req`). -default_bits = 2048 -distinguished_name = req_distinguished_name -string_mask = utf8only - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -# Extension to add when the -x509 option is used. -x509_extensions = v3_ca - -[ req_distinguished_name ] -# See . -countryName = Country Name (2 letter code) -stateOrProvinceName = State or Province Name -localityName = Locality Name -0.organizationName = Organization Name -organizationalUnitName = Organizational Unit Name -commonName = Common Name -emailAddress = Email Address - -# Optionally, specify some defaults. -countryName_default = US -stateOrProvinceName_default = Illinois -localityName_default = Chicago -0.organizationName_default = FreeSWITCH -organizationalUnitName_default = Blade -emailAddress_default = - -[ v3_ca ] -# Extensions for a typical CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ v3_intermediate_ca ] -# Extensions for a typical intermediate CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true, pathlen:0 -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ usr_cert ] -# Extensions for client certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = client, email -nsComment = "OpenSSL Generated Client Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment -extendedKeyUsage = clientAuth, emailProtection - -[ server_cert ] -# Extensions for server certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = server -nsComment = "OpenSSL Generated Server Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer:always -keyUsage = critical, digitalSignature, keyEncipherment -extendedKeyUsage = serverAuth - -[ crl_ext ] -# Extension for CRLs (`man x509v3_config`). -authorityKeyIdentifier=keyid:always - -[ ocsp ] -# Extension for OCSP signing certificates (`man ocsp`). -basicConstraints = CA:FALSE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, digitalSignature -extendedKeyUsage = critical, OCSPSigning \ No newline at end of file diff --git a/libs/libblade/test/ca/intermediate/private/client@freeswitch-upstream.key.pem b/libs/libblade/test/ca/intermediate/private/client@freeswitch-upstream.key.pem deleted file mode 100644 index 60289fa059..0000000000 --- a/libs/libblade/test/ca/intermediate/private/client@freeswitch-upstream.key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA7QkR1NA64HPzuYYko7LTciwCWu1JLGuA3/7DkskMZ180+sQ3 -dBG4UjujKMRc0h65oFZc//WYIfmfUznLvLsRygghlevPqgGRGdf9WHIMjo9+hLM6 -MgZ51Eqqydh42L7sen/2bO85gh/pfxno3+uPFGIJtX6GFiJ5Hp86wF+cqnfRRUFo -+0L34+rLY08fITEkTbPjNg5R2jcWa+dWJXIJi3pud+ulWPTKalYiUvsqN8tucjJI -Zb279yzrxsV2qjRqHBCToBj9/kcJHD8gKrpEf1HsiLLJ7PEAID1fMONTL5sVXCJ1 -TXpjWNZTlcTCCMAhrEghGMZV0FIm7GS//naqywIDAQABAoIBABSZ9TLJ5lQbv9Mg -FY8ku7vwl0PP28xAi7LsMZNQZgOWAsTIyQkNgTekd0nTxz177iZBW1PjxJUvXOme -3FZK7ADjNAgTtrjP6gyU+S/2uaCqWBSwfx5Z8bzBwJZKejZcYbFD7ecJ47WrkF+7 -oMHVd1oOK0na9Ux3Mo+2xyRxKuyl0ngwYp71pDh2QyCqZUXBEeY/gD6rPOf6Bt02 -+fEjsePe0wGJUpiTpThwJuYH8nHQviXIN/zEK5CN3kOFC+fVVRLrXENmOrVBUMjC -l8falZza/dtzStDDKsC5gQw+GZM3TC/1zo0eb+uzTeTLDH3o5GWsCAKC9MMImZo/ -gu9KkgECgYEA+Ecnv+nfAn6REU4jztFYcAHGMs0dEJPJK1AD/TkwMYC7Ve2uUNuz -/0KsKiz0SyqhQxsvBHnj2FVlTZCxGQFe2KhVF3cp5miALMHlH/mbQyP2nnoO2+Ny -A8GBizPNvugdDKUrnj/6jIp6S+2jhR5OfEtY2KgA5QjGRMIxndhsNo0CgYEA9Ghm -Hk+UtutZ7NPXoZBH0iuBiDj3NOfqX/84mUb4XAQ+EVUw62pGpTf2OU8RRuHgGoHf -aRcrfga/wtKx3/UA2m31xNhIWIHSGE35neyzQQXBp6fB2bhUCpPBgFCJz+fQCdOj -fcCw3vrMf2H5oS/0azIsgsDRVp9lNAOtgdfFXLcCgYB5IgZTzSBAUE4o+k3gLyWN -6F+yE38VwnUJC84Wcxt/W4aLIx7EVp0YcogbP7mlHtR1MEMdVPcEao21bV3qjE+h -N2fkvgAUaXH35FYM5rSI6nf91CGByROsn3G73/eHKCpcLA3+9MoiXcHTX8tDPIkg -fYaIlldxZ3mMvI6Gq7wIVQKBgQCba0P85GhSRalCg5fson45dPcC9A6ncw7Eityo -A8xtXzlE9mKMYWGZMNP/r3ryEzLaSFoUTuqWUp5gunDoVLl9LU2LJmoi9jLux68D -MQDwSUPTZEdONvwiWcFD4nMwZV4S0aV2kzEmKmAeZOREDuWjwR0y7IByUBwgDnKo -TdiwUwKBgQDJ8OYzNPvp6wJ0vGg3s7ula8tiHCPmFCRJVLV6H1a+UDQD4MY2DdFa -MgyxbetwglrSJNI4KJnc+WRYKspvTHlIkkr/GyJRW1EtBBED+drkOmvZE7vc51mN -vj79bK66jJls/ul7YQxaKPHhB77zVNFJzWfZ8BrOCMhNTuxIE1xpRA== ------END RSA PRIVATE KEY----- diff --git a/libs/libblade/test/ca/intermediate/private/controller@freeswitch-downstream.key.pem b/libs/libblade/test/ca/intermediate/private/controller@freeswitch-downstream.key.pem deleted file mode 100644 index 6a516337b4..0000000000 --- a/libs/libblade/test/ca/intermediate/private/controller@freeswitch-downstream.key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAwEA1njlU4qAG2/KskXthKBI35KDTND92Dqg6gkAvbC/IGEJJ -yzxw7Fd2AjNMAbNLuaasK9HFRwPhZXOLQjvl+wjwtBEAgGw+gLqrLdC3RVuiWlxG -sbfB4tAYn9Av44jURYc1Prprnvqzl8+DIU6UTuRh9JimoyL6NC4rqgcvo8LjR01R -Nn27RdyeO/VhDjdiU2/vC/OujUqnInhtGvTB/KrDJtxLEcl15zBGe0PBoolYCF2+ -8FS2cMFw8y2aeeNeOfvjlzMXOxGG4vohxUNx/DZh6aNUzbh9Fp7gvJQ8ZRsRNqtI -3AgGW4+7Bt4US9ekM8RQjRb51Vk/NcFhOKejswIDAQABAoIBAQCPBjXdhGF2R/9S -WnOvt85L9WHHoS3/TMcTmGwOwpmFLvb5tTcZD9oiud59PJRrH2xSrYChCOpvLp/c -zdzoZY9u9vO7wnpREDZfpn/7Ea+G1ekuuD+Pr1l61726BzPZXs4s+63NAPtXxsMd -SbAQc1k6aAXH5ljyPO9PKpopYDc86FCJwPikedeYAHzRG7o5msMUiyTQJkiti505 -cpK+YC6F0KxLzhYKKy5UlWW9J/j5rZf1UkK9keaP+dWxi3u1177aaZh3f/RMl04I -QFxhfIElyuzcJK84uC3Ddmwjk88ix9RqP3Ho7EY+ly5WpHcuHJVXxKgOQXheRYeH -4GQN2nBBAoGBAPOwQGPrwYkHjjWUAZ6NAvhxwUfJipjcdj0mF1J9aHzg6nn3PpE3 -nbFipPGdfTIf+v6QdpQJ4BEwCEgXNctfcqyu5UUv6S5TR4vAIpkuffA10GQaxcX0 -OXkdi/KgcHle0RQW+FJXMBfkr7DXidMy4XFK06kp0VPsECrINpM4B8hJAoGBAMn2 -sCrHn8zq3N1hO9gRPCjyArLLJEwL1QzwY07oIjPQFUsIHmt9ixh3VcipMoChqxfn -dPSWqeLiq/t0e3ekSGLQf9juivoKZzv5KQqFoPg8/9eWnM988OuXQ525AgnaQIq2 -Sb1I+Yo5pS+PUShHrDBTI7Di+wMkljERZ4qy0WQbAoGAdkXU+qoyBI/mNZrgLlPC -XVLYvD7VRdu6h3M1XpP/YpzHMOsPMuwLXUzDQYFugiWDbIoxAyjH14+4dUTOlyZ8 -QdOg8zONuS4yS2G1aSNnfG6h9fQIiUs/mcj9Y4T7Ee0zDM0ZON2YOgCERRBXlGnd -gV8P28qwDktEjX8e/dTz8gECgYEAugjSHZXkTQ3KhOGcDltR3yWN9sPIm4QKq/CC -iZyqZK+37XV9D+aEyfSiwEOakYJZ55r80JA3zRae9PFHCd36D4ufOGQDAG+0yDmq -5FZTAFawFBZYO4gLI/giAJb6mbjA2wUux30A36JZ1oVdbI0YvyrWJYnvTeXVsz0k -803kMyECgYAZW+NOhX4mXr2N4qfpQqE2JZZCPY9SlOJLwbS117xXqeOuE5Ht5owr -DUO7z5Ps5dvDFdcvWf7wE4L8ZTxUNywFUbONb3dIH7AuIQXn8wcu3LqQbt15g9f3 -7vpm6snlbgebSMWarvE+W8DhklceuYizodI639HSjd8qNqCsiVWLbw== ------END RSA PRIVATE KEY----- diff --git a/libs/libblade/test/ca/intermediate/private/controller@freeswitch-upstream.key.pem b/libs/libblade/test/ca/intermediate/private/controller@freeswitch-upstream.key.pem deleted file mode 100644 index d09a16cf66..0000000000 --- a/libs/libblade/test/ca/intermediate/private/controller@freeswitch-upstream.key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEA4t5HuHuWElHb9Pe5obw/bSSjhmj3C50ZL8Y35oW/kSkWOWdF -HHFtqpzkUXFZJagmky+tyJf7iLML+OCZVJT0vtN0ray8ZPyuptfPfUffAQgE/iKs -ou1bbZRs5kvYmiJbyQNQxzI6xzeNOqkTCb3o9KJhQke8/ppMlEl2wCWbFmgm7jqH -GDy027LRXphU8FkVT004MSiyb/DAAWgCXLvSW9QP+RcFkU8FuAzLrEdU+tcp2i7a -ngjB9Y2qbhWZLrnZiSMbtq9JICdNqmG1pNMK+3A6QK+uMke+DgAb7ODA91HFJlGq -bv7NB0AjILfNDNBGRs6LOVld6P599eMSI82Y0wIDAQABAoIBADhwdAdBN6R3GPFo -b5X87wqIAuZ9VnhdLNblySJgQ7gpMI43Usowrce0IFjiifsEShRz2Bf/N2Rapq/T -sFGKfRi8IlrSjkvRUOHQ7p2MM75d8GAI4EnoIsawFid01v4BbjQjzwS/SkAlYc0m -IsZZqIqzmt6SWkI8wLBjVleXA24fIvzgb/k0scAK51Zu4sgEYQmZYzzIdEjPoaj3 -SgU3YgsHFkTl6fwu56BqIyXIymmKIYmMyljFXXvEzqePsLAxH3nBoOjViIzybCRz -twoCY2Ww3ddNJpJmldccs+0pB0i+rdnxg8lS0QCExI8cLNy8fzEQmKX5BQtGnd13 -8dO+0AECgYEA/gx5Oe5GZGMFtwVkUpAdwlGHB4chaX3BWAG2aHM6qmEoV6GntQog -FMko6ifHY2oFt7gLR18bYQqgvpqkRlFieG89Y5Crsz6rSqu9HtBezuLibQ+9DRaZ -MdGDrNjZ9gIv4W4bwakp9SHnvIyVDXzvX464XBF4Xp7B3kGkIPkQh4ECgYEA5Jxc -3DYy8G2svF5hln3DmR2EKsoAfC0pdq+pxCxPDE5v6GONuwPnSB6YdP0nAZuMr+CY -VZuiajH8lbZTjKYLAvi31B8hNV7s68YegUKYM21mzlGvlc9agjkuIQsHullHN/8R -A7wuXoBC93m+0sQ86gX4Yw56kzHvmt3bt/R2qlMCgYBzYazpP6veyg59akh/Kw8p -AyglphzpsYDPfK+gzrzVRx0wd64Yjkm1xwr7Fif7odqI72DIAI0JzO7mwotbmHj1 -o+gowTsKRKs9VbSmOxLkOa2GxQAi4qGfO73nEfIkRigC5aRbl34D5GtAekT0BEsf -hk17G0AlEUuRqxRlGVmFgQKBgQCybpjMCEGaBwBbxg7FN0QDrlYKT8AxK87BJDqN -M0g/grk12P42icVrNPYp2a0oRBB69gHwT5lk6b8L21M65B6UIyzYE7QHxB+HpwsI -OMIy4aDsSDWT6FPscFTg1Ysil6xOuHa/Q5GtkM6z+gJG34Pr5N0J87MYUFGDvsZP -vi8goQKBgQDWvwsSBOdVp0A5CxjjCDdIZWSg9VnHDulNiKg1uk3Ohg/N12ZmK0ZY -HBy5hHSYBIx0PixfdKC6fkjbDdWCeKCoLqeUN3NU7WyDb+hnvDHI4uYU12CkXBnE -sSdNVzfzCouLg1czYdxnlItwYRc5pTnTdEvdZJC4lNDSvrx+wM1GeA== ------END RSA PRIVATE KEY----- diff --git a/libs/libblade/test/ca/intermediate/private/intermediate.key.pem b/libs/libblade/test/ca/intermediate/private/intermediate.key.pem deleted file mode 100644 index 8a2f0e7b2b..0000000000 --- a/libs/libblade/test/ca/intermediate/private/intermediate.key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKQIBAAKCAgEAsiVjUmZX3PrCMTqIQhcdSXYJGexrWMP64OTgj86dw517Ol+/ -aZE70LtWRx59dvnIOt1r+qryv2k1WbpDbAIkgIiWsr24r3RIuwHxaw7wOeu/0TlP -H3pTonmoPHkxrcgUzt8XUpQ/UtVrClLiUwwoWFzJ38/V0A1laXMcIGgzg70cyjiw -pjHh/PGfTTIo0r5FThbJ3d5ye046D8O3HcUe3VsTFQW49RayBVRHxv5Hpn/VTqJZ -77fH9cEBRUIGHLO3s6sKljSDdNfvBUKHsJp+lmdN7niCMyjWWpKtonkOvhKfUtXW -BFrxxVCs1tRn6bZoew0vGakS+IcMtN3brvHmpcQMI1qN6wmJIAtGlDMAkT+d5C9V -rZ+JpXs9s8aXG1RzJHwn2wZ+65vLjz9G6U9DUKMvX6wj4gSWcxmpOJpv7VNPk7Io -xhhGNDiTdH+BQafQyFAFzLVU4/oZUYSB45gAJsNKO9g70dl3Iz2K+nEuFXcExUzY -HQ+YXEuAV3IGUg+Q/fr/mQHM4UlZ1isws/+9qEVWZOB68ObxSGLc+8S3qQpSdYeQ -Ed1qPMMou9uHzL5RyBqns+1PxqllH7wn1NfzuAwXMfmvhdxIX3uKcn+rT3xXx3Kg -8mkvo9EDOKAFcaYHZ8WEuC2hd+4p8j+d+BAc7sxtgIIU/jM5yHaQVlh6EFMCAwEA -AQKCAgA4vlX7qiO0fJ8cZSN/wbMPciyF+FtdA9fGiMDKraps452bw2HJ83vVCcb6 -kkiue/N+ZIb/ajI2LAHVWdId9jTASEGQH4RTRrvf7UeDrVdxa5lGwHVmdmVrbErd -MFFVpFSUbFUWdagR727P9ASpJUc4lh2rT50wTwQNaZ/85pP6E2O3OgVyepMcKa5v -PVnpfre+nt2f8ToP8qPl35ZVQjOJmHfki1UVpCwCLI1MYjRaYX+FM4toIubrbZXF -BLnDrK8H6KRPodx5fEpjJ4TnCN7nc3JMUlBOkWRtpyjthpfejTn4fapU6s715bOY -HkIXHIX9I/7rsoIbbZDrj3tpJx4rCM1SkbjIylOvgWe7fEa5awiHnVQYL2Mwx60w -Ag35r+ZvChu7+rNP/xXh812jNPOoFfwdXktJ0QSIbZp2dJGJLwaaaf2WscuYtKii -0L4eY4wuJFd08nIIKDSxx+U+kO9JImZE1gxrFZJFBkt5fR1HtiK5904AUExVHcFC -Bkkar++TztO4rZSRm5kcIQQ8e0zFFSnQNX3FAgRPt+FG7Rqq2TbN0QnyCu6WtY/a -66sUgFoJHv/kkiukUYZgzHLsUuQn12U1hl6hPKjxQFaYUQU+ZDVuT8dJ1C/XQbPO -V5REaV5gcATsCIvcWIb6R1gqqT6xaDK8AfDUdcBG7RAZFP3g6QKCAQEA2Usr0l2r -xUSSfvQEd/YgORwZaCBmDpPi+MmLDZGij44aUemo+3QlzJBu88sCQRHAHBsxshA5 -8aQxb2gLyKyhbYjp7PQwlvJdWXrsTYtQaJ5j41x62PDqZg3EuBs6hmmpHk9srl3J -RS171C4GrY+hvCetpfBFjvBpGMkS5xxuf7ghtfEqihHeWEfhoBFxCovyTcEG5EpV -bIGkAQmEqjihUkwqSs1beR7Uo3lbBQv7TJ8IpqJoO2KguuCmrqxJD7blAGA09XoC -Ndjum3/xLUVv8X1aLa3NkGgsfNBYyEVOxmbxmtrEXmrOQ7ryr6XUQcbiWCpiRJUB -le1UX5wOgOP25wKCAQEA0eELKk6nfhizZ4RT9Va5W70gidIcXk6n2bVxACybj+cZ -yDMClyYQCREl2N/ndxWzlMAJG5v8+4fzhUHMvzh6HJirdJXWU0AD8ujPHDTEO1Ot -3S8GXj+q6t9Q2Ov1bmAHIlT97rrPqiMKjgl6NrCg8LUJ5FiVqAONlPdb/vk7GRvi -KdyccJPwEO8hXWljXRMx0Rb2g7OWXfTWxTi3APf5HVAYWIpPzzAAlNfnM8i+rPxM -YnWPj3BZXNfo2T5dyL8tFvW0aNp8wSe8y31FXtanwzfkhEune9aeS6me/SJnTuVZ -D4IVS5QmBl5uxp9EM3f5Q12wx8wQf6k7CSt26IKptQKCAQAaWwjEqkHkWm3eYiCM -oFjGNIdMXumiCQP1oxRvn+N0wAqnNs0dOrg++KHMhioO1GVVw2Kis18j1QN9/MO5 -Il8uFvYwnGmsVVdHPCafPS+SkOuSryvjVk1H9ZGPtxXBKd2uZHnNKGj6MAsd8Ds1 -H//A/5sLTnpRXQ2SSQk26PbqHN5R4B+FwacTVBykupjYa6MHFUuNswprb8oBqjLi -Jp5CiiRzEDdxGHE4JscIdKyVXZDCDV7RHSRbplXxR8pQ0qEyC3lA8PyFpXtDdyA8 -mnh6dPbUJYmSY2BJ/0dVezqTy/awDqrUvOWpx2oaLeXx2HqpsPJcWSppEfEy643C -ymOvAoIBAQCBw2pr1gWo6QzDTAW9AsnH9r9PdyEjDe6ppI0hVnM4HeLK7P8FBPuV -H40O8iDieAB4T+NRtrhLrFrcYTp+YCTf2WToyFujTUkjvt2OyvEo3Sv6PUDqtOKw -JTKPbBRrEeRXTcVS/R24S8IS37k4ZyyaptRe4oZlQw0etXGjy+TGOX8z8rqmwFEF -p1QxtR9CRMPgSxpPg5HMtby0Y8SCTM8xWHw1Ag8mQr+ZR4QjeFKsEbIIjjccsJIP -3U6SQwUpQUpXj8LjsXLA2hjYl7N0V7OR99TKFxyObLuifFVYnRTSqurNs9gGyqpX -9br4AzDfwaXUCPFsFrd8tt1RZhY229KhAoIBAQCO7m9O9VCPVff5G8ZPyBx0dBa5 -9izwZ+eOJVXAMJUlw6uA5rgzne6di3JS8IOzaKOrNVK2cXESbS97n1pBybqqHibg -bBOMESsoin8VdQZVic5rGYr3f8llMrv3yaVK8UievCNBdVPXlBY58uVyZIxrkVyo -Xv2x/+6EcarY46CT874zLhYHRcq/ZNWfQpUx5V2ySO/eNgSbbob4dzEdP52HpPx1 -JAGpTHiOkicORAu1RWN1HvGxMITz6q/pY81cEwOI4QsQJQs+Qk0xMKLqW6f1EZY1 -dgvQq8YnwSo1fOrVM0TL5jvbXK7vRVT2zQ/RkEMIza1qvfeGbpCDD8/O21so ------END RSA PRIVATE KEY----- diff --git a/libs/libblade/test/ca/intermediate/private/master@freeswitch-downstream.key.pem b/libs/libblade/test/ca/intermediate/private/master@freeswitch-downstream.key.pem deleted file mode 100644 index 9a7ecbaa3c..0000000000 --- a/libs/libblade/test/ca/intermediate/private/master@freeswitch-downstream.key.pem +++ /dev/null @@ -1,27 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIEpAIBAAKCAQEAyvJnIg9cvRdX89PPuFdXelWX7/O4dFePyYobIxRAJb6INVtQ -bHzD8NXjRpspA1WT1YJpoIz/eVGWAZvYFj9us3uocwP+8KanQrP7RtF7IgkuTbMj -//YN94XFyas4U0F6Kp9HBkSc663tgHz6F9goo1qYx97n1DMmcze3z+/1QmDRA0f+ -Bnsqd0YwZ6sOD5Raq6DBNu+tpDQuYxpAoYT1KWKysDROpr0Oh9A8IyZfXB0fcp7L -FPNYdEw2vfDepCnAy8yuwQKBbRRkSqxZC3W/C7b2xus8i2a6SbcJHIH8jqCrVzLh -xnyEp5zLW4IuiMmT36P/UXCiuqumt/2RxKZcCQIDAQABAoIBADimja9uRl7qQzzm -5Vb52otllTIAAH9JafPCP2z9XCKtGux5/uspsLBrpDOzYDF0E/5HlyCf+zhsU8lD -LYCYWFh1rkHc3a9jddEi2IOeOhb4JRq/ZM8wahmsF9gBmYlz/5wiNftD7+HB/Uge -mtlJF57xzTANwvzzAkqrRP4gZ4ANct1zlqfsSojObV7a8BN7nk5xWw9lfQ2JmB8/ -ZLcXqKOyHZzH7A1XigeBoFglONWbBkxaziWiTld5QT1CiL4u3vke3QefLEUtOQq0 -ti8iaapS9q/qMcBzJuBvlEG1QdrHpz7moLlinplnLJy0tVdPFBr2ICX5im+SxHik -nUJd+QECgYEA90618dSSxGguB7EWm51yIuLw7TXlh3FPzD3O3FNhxcmdfd9HrNRO -lJYev/z8j1c2YK0F2n4zn5XRyiu2NKa6U3EpF55+LW61WibkK494HwkzLpRWQUJE -aoDVz6iNhmZQDMTecKl6xVJSIhYV2wf6uh+PRbxlxNAyFIB0dPf0cLkCgYEA0hSI -XM4l0w3goTVqAVfbm92gRi6KEq1iMO6kXTCMs3SN6b3X8BW4AgD6rIOszrhbpkqp -Y6qkPSsOoo0x0er4ErQIZgnNH+eDQIxRaj84zpkwj8NKw43NYSurK9VGDPsJz6dS -dcJPIe6jKCrYPp/XDx8fZorcAqXOHscKFFVsfdECgYEAyYbVkzxzYSO4JsJzNtol -cTJXvCWIZke7DCdt03MLIJ77/N+fS8IySrjOVAr3UGN0R3GXbIYc0TXIICRgtSUM -fwSexMV98s3dcJpyouCltTzM/W8ZntI+aD+WfELRGS10nAMtdMdW6Ub88RPoOXWW -JmejW+N7VteFh9lpjQuloNkCgYEAgwTtOrwS2PsZslDmyOmrfB0PvVV/JUDfMVdU -SQ5jYfR6IWIWD5TsCsvjir4gg1h1SFPeKtuczM1StkxK2vmpN7jyV/ka5h/0OsiI -ajP90NO3dqG8uhNxGH4spgzAQI48Qza+ddT2l1oGhaGa9guoC7VEVyaZKkmQMJ/A -CIhyPlECgYAxxTfosu1A7ZrceRPONl6rgVFGoWlqsI5COL5fcNmrl8rGfTkSOMQF -ZPNO/7rl/3Ziaah6CZf06qMSG9atVfOJ9OQ6bPcS6JLSIHGwU9NVlAjGpFSAlM2m -/KEffzPMJlyz6c7sXLt1Hb+hjO15yYsDpHZynFSSffd91GHNx8Lhew== ------END RSA PRIVATE KEY----- diff --git a/libs/libblade/test/ca/intermediate/serial b/libs/libblade/test/ca/intermediate/serial deleted file mode 100644 index 59c1122662..0000000000 --- a/libs/libblade/test/ca/intermediate/serial +++ /dev/null @@ -1 +0,0 @@ -1004 diff --git a/libs/libblade/test/ca/intermediate/serial.old b/libs/libblade/test/ca/intermediate/serial.old deleted file mode 100644 index baccd0398f..0000000000 --- a/libs/libblade/test/ca/intermediate/serial.old +++ /dev/null @@ -1 +0,0 @@ -1003 diff --git a/libs/libblade/test/ca/newcerts/1000.pem b/libs/libblade/test/ca/newcerts/1000.pem deleted file mode 100644 index 8e915f4784..0000000000 --- a/libs/libblade/test/ca/newcerts/1000.pem +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFtjCCA56gAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwbzELMAkGA1UEBhMCVVMx -ETAPBgNVBAgMCElsbGlub2lzMRAwDgYDVQQHDAdDaGljYWdvMRMwEQYDVQQKDApG -cmVlU1dJVENIMQ4wDAYDVQQLDAVCbGFkZTEWMBQGA1UEAwwNQmxhZGUgUm9vdCBD -QTAeFw0xNzA5MDcwOTI4MDRaFw0yNzA5MDUwOTI4MDRaMGUxCzAJBgNVBAYTAlVT -MREwDwYDVQQIDAhJbGxpbm9pczETMBEGA1UECgwKRnJlZVNXSVRDSDEOMAwGA1UE -CwwFQmxhZGUxHjAcBgNVBAMMFUJsYWRlIEludGVybWVkaWF0ZSBDQTCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBALIlY1JmV9z6wjE6iEIXHUl2CRnsa1jD -+uDk4I/OncOdezpfv2mRO9C7VkcefXb5yDrda/qq8r9pNVm6Q2wCJICIlrK9uK90 -SLsB8WsO8Dnrv9E5Tx96U6J5qDx5Ma3IFM7fF1KUP1LVawpS4lMMKFhcyd/P1dAN -ZWlzHCBoM4O9HMo4sKYx4fzxn00yKNK+RU4Wyd3ecntOOg/Dtx3FHt1bExUFuPUW -sgVUR8b+R6Z/1U6iWe+3x/XBAUVCBhyzt7OrCpY0g3TX7wVCh7CafpZnTe54gjMo -1lqSraJ5Dr4Sn1LV1gRa8cVQrNbUZ+m2aHsNLxmpEviHDLTd267x5qXEDCNajesJ -iSALRpQzAJE/neQvVa2fiaV7PbPGlxtUcyR8J9sGfuuby48/RulPQ1CjL1+sI+IE -lnMZqTiab+1TT5OyKMYYRjQ4k3R/gUGn0MhQBcy1VOP6GVGEgeOYACbDSjvYO9HZ -dyM9ivpxLhV3BMVM2B0PmFxLgFdyBlIPkP36/5kBzOFJWdYrMLP/vahFVmTgevDm -8Uhi3PvEt6kKUnWHkBHdajzDKLvbh8y+Ucgap7PtT8apZR+8J9TX87gMFzH5r4Xc -SF97inJ/q098V8dyoPJpL6PRAzigBXGmB2fFhLgtoXfuKfI/nfgQHO7MbYCCFP4z -Och2kFZYehBTAgMBAAGjZjBkMB0GA1UdDgQWBBT24ScXvFFEdGFsK+X5SxmWnAmd -/jAfBgNVHSMEGDAWgBRaMzl9Nc1p7PgDWff+pvYOddMlljASBgNVHRMBAf8ECDAG -AQH/AgEAMA4GA1UdDwEB/wQEAwIBhjANBgkqhkiG9w0BAQsFAAOCAgEAgGzDCfJm -weo6oeSFmSLTmlBlTJZO+7igFWf8tunmTkg8wvKe+lCyDd2efNgUocI/NA+X4kRj -YtDH+hq0H+JlDu/p4y4/t6Srx/dh33Ow7eCv2wtuSCeK5Y0euysXhI9gmPquUGOC -HlHkmQcG03NbbrWt0+4IaPAaKxMuV0FR7KArudZvr+8gp9S8o0AkQVFZSbW41HQe -a7DAJmLF0vLQWoVz/YltKjwAMs/ws8OWxUdvcOA3w6XmWmjAFn5hc2MgHgu513c4 -Vbq0535ghU0Eneqc23y2ELa+8hbn5yS5wcK1AS2HG4VoDqOJw+pv4Ko3T33mCR6X -bUABSB+znX5kEZn8KQaP8sLm07kERGjCI3FLPscM1S851tah/iqBgddlIUn/YNpM -9uYQ2PWu6UWvqyZfhgVIlb2LYJNERtKZPeI05SRIbUW93wUTiC6A93fl8SEE7XHa -LMJt6+HLysR2IsXLqlSRZw3rIoT0B3G4uS9Xop89znLAknrOI57OvVAMLaeBrtkl -jepE7RrNX6VcyEY+Ar1p30ax4UJNxjxd3rszIznccerWQzuLo5wYUkuZEfNtnAFB -Z/4qlIn7wkbRevafgmlf/bhP6ZkeJFhqEjOq36Zci5JrnRu3rM/+Vex2ibHVat0E -IZjeGxeofAPEwTaLfPJT7EIWZ+33ZHMcz+8= ------END CERTIFICATE----- diff --git a/libs/libblade/test/ca/openssl.cnf b/libs/libblade/test/ca/openssl.cnf deleted file mode 100644 index 5a44dfb4b0..0000000000 --- a/libs/libblade/test/ca/openssl.cnf +++ /dev/null @@ -1,132 +0,0 @@ -# OpenSSL root CA configuration file. -# Copy to `/root/ca/openssl.cnf`. - -[ ca ] -# `man ca` -default_ca = CA_default - -[ CA_default ] -# Directory and file locations. -dir = . -certs = $dir/certs -crl_dir = $dir/crl -new_certs_dir = $dir/newcerts -database = $dir/index.txt -serial = $dir/serial -RANDFILE = $dir/private/.rand - -# The root key and root certificate. -private_key = $dir/private/ca.key.pem -certificate = $dir/certs/ca.cert.pem - -# For certificate revocation lists. -crlnumber = $dir/crlnumber -crl = $dir/crl/ca.crl.pem -crl_extensions = crl_ext -default_crl_days = 30 - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -name_opt = ca_default -cert_opt = ca_default -default_days = 375 -preserve = no -policy = policy_strict - -[ policy_strict ] -# The root CA should only sign intermediate certificates that match. -# See the POLICY FORMAT section of `man ca`. -countryName = match -stateOrProvinceName = match -organizationName = match -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ policy_loose ] -# Allow the intermediate CA to sign a more diverse range of certificates. -# See the POLICY FORMAT section of the `ca` man page. -countryName = optional -stateOrProvinceName = optional -localityName = optional -organizationName = optional -organizationalUnitName = optional -commonName = supplied -emailAddress = optional - -[ req ] -# Options for the `req` tool (`man req`). -default_bits = 2048 -distinguished_name = req_distinguished_name -string_mask = utf8only - -# SHA-1 is deprecated, so use SHA-2 instead. -default_md = sha256 - -# Extension to add when the -x509 option is used. -x509_extensions = v3_ca - -[ req_distinguished_name ] -# See . -countryName = Country Name (2 letter code) -stateOrProvinceName = State or Province Name -localityName = Locality Name -0.organizationName = Organization Name -organizationalUnitName = Organizational Unit Name -commonName = Common Name -emailAddress = Email Address - -# Optionally, specify some defaults. -countryName_default = US -stateOrProvinceName_default = Illinois -localityName_default = Chicago -0.organizationName_default = FreeSWITCH -organizationalUnitName_default = Blade -emailAddress_default = - -[ v3_ca ] -# Extensions for a typical CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ v3_intermediate_ca ] -# Extensions for a typical intermediate CA (`man x509v3_config`). -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid:always,issuer -basicConstraints = critical, CA:true, pathlen:0 -keyUsage = critical, digitalSignature, cRLSign, keyCertSign - -[ usr_cert ] -# Extensions for client certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = client, email -nsComment = "OpenSSL Generated Client Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, nonRepudiation, digitalSignature, keyEncipherment -extendedKeyUsage = clientAuth, emailProtection - -[ server_cert ] -# Extensions for server certificates (`man x509v3_config`). -basicConstraints = CA:FALSE -nsCertType = server -nsComment = "OpenSSL Generated Server Certificate" -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer:always -keyUsage = critical, digitalSignature, keyEncipherment -extendedKeyUsage = serverAuth - -[ crl_ext ] -# Extension for CRLs (`man x509v3_config`). -authorityKeyIdentifier=keyid:always - -[ ocsp ] -# Extension for OCSP signing certificates (`man ocsp`). -basicConstraints = CA:FALSE -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer -keyUsage = critical, digitalSignature -extendedKeyUsage = critical, OCSPSigning \ No newline at end of file diff --git a/libs/libblade/test/ca/private/ca.key.pem b/libs/libblade/test/ca/private/ca.key.pem deleted file mode 100644 index 9c305f8510..0000000000 --- a/libs/libblade/test/ca/private/ca.key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEA3Pt3X1j8YaRuGb4ENkhfazwZl0K4VlaPhGj4h4wiL5S2Tp8E -83HoRkoyQRX0fhKCrHtjNucOODkVbf+QMlv1mgEwCq+3SIEA6keBzsUv5sahunfP -d+Vgh6+lgp1sAfjFuFlxrRvighO/yHHKE6P2BBgIz3t5QSakE/fLPwejZ98dacyA -IxklzLvt4xHRVP7rxfiNFXKRXHsQd1iaWGSUBNMkUspCl8wO5IAPX75RiFGeA80I -jZ518YVjiFBjCdzQfJb9iGJCGzrOcPJahfum+tzyIO/rIj+ldFyLPY0wbpa0wKeF -58HWt52p3HmKnK5FUa7L8RNAfc3/H+6qyDeBFx92+T6J30q61dcmPayKooUJNsTK -slrZ5L2OicWZepa/Oc5dagyzGEUc+Z11Mgl8/4pT4rUOna29v1d8+StJPN8XgWAH -xmwpZ/cY/9GluSq5oB+6PTPcQ0aFHHUAI97QqfpGOeAWjtVd/3YUcNo82Pa3577r -Rgh55X+XEySQmBiPWNOsfuCZZvYGOkLmby1SYR/LOwH8opKJyG/bOiZq23aaTPkm -EQQSLRzsKxWc2jlE/UllpYX3FCu8nFn+L7Tam495IImi8FrpEX16ZpTGhr7YnfbO -kMYw+LaRA36U55e5DToJAB5TCsC2CLhk8QDVoIMPfpYpY4XpdmA4EfDHOG0CAwEA -AQKCAgEAiAH9pqGONEqPuShKT16b29RRq9dUvU7pZgV1cXe+Uqqkyh71XSBuZVSl -OYnZwP6DjsUie1gaWGBJ4Dm69kPDFdZFS0568BT2CzuXmTukD9WRFMNI3fI/R0PE -Cm/5Wf1TM/NZE8Jl1slw8F2Ykh4H/N0ODyVfq8mskt2gKlr5J6Ua5VMISpHfwfKo -p2j//eAoHOCtdNXewZy8tbfCx0SgFZgecxYphmQBhoGK9NKeO9h/+Lbo3MD6tnvy -lqNjUV6mswf7Y0WWikvXY4zGSlBopV33aG5BugKSQtvylx+e/3GiLjDtKYcUME7J -jPkBZw2bfHqo6ud+ee+fZnfuhOwkdoHCGPA4aN7L3B19XJBKsI4zAoQNlUAteegg -D59Fdnq8362xLE0F0crEgwMFYj4Qg9jy12em3iSvuKa17o0FuovGug4nHiQQ5asH -nmjadXNfM6xAoQqCgbwjrVYD+i+/ofFAqDhPbjH+nOxS8l4MD+0i7nzQAIqIjsvl -S5XM548ufxcEgwpMGc2bbJS5qg1weIgHZGT/RqnzeqFfHaJ8VN33Lbk2H5w6Qj87 -QFNqE6ZxFnf/k8FRF1QJB6BhmkhExvYgiK51DElnkinDDa6nkbwlkr1dE5zVv2zQ -jLmQdBoHw2dBWEmik0lZ4m6rIvMD5rkR45oNPcyZ2wA8dKgr6AECggEBAPjmq0vK -ur8RSpqEIXvI6dvGNXayGAFM0KLaHYfB6+qWXP6j+cn2wJHvH9sxl9vmUdE8auj+ -DaoaK6XeFcvBryO4+EwzrnY4eVU6QW/UiCgmSnRupLBxeyQOSgbok+3gMeJieSPw -CpyH5cC3v9mWpg5X5dmm+ENUqv3d4hjsZzxwkJ/k92/29F7eaCVmlEOPw2skkz3O -4BBznOSL9foKp0zAx/hqV2hkJmnb6DK14D6QkX+A0o8mOvhq1NjJ0isMUtllVzkq -Lro3J8NEwkMhwYfVMOoj/URdZ8iskp5T6ez/BmIPE5zE9F8ZKmU4PkmpMoHISzDz -5zTJOBCJ9AslNuECggEBAONI81qE5gxk1DCXLkfdCDe1paoy2DTGFX2MXTeDipv+ -C466l/odu9JQZASfXgpVkyjAPKFTCgAZL20V3izuk2izskZKN16KaNG3SJWmwWx1 -o2Gle2Z0Jd8AqaXvPzAKDFio/6MfD/EQFzOv9+BEBAlCFCz39Q19neSarhS6Ckv8 -kljsOambnjGtSliPZkrFueG9BLRqaTCU3yZpXsS8DqCVTqw4xmNcMGADkhn568Jq -664iFXjD5aiAnrmBKzW7GLY7mbH4oyxmL+NNj0mwjB80evFZ8RIQuJ4tmIRFK0vo -czNWo6CPOVbd4qMbhsHk4Pm1gH7LHbbT1PFlrsZ0Tw0CggEAWFHJoLhMMbZaCaAv -HXR6fzDDEd46JGP0eIT7C4wlQXWfg//9h8vWIzJ91FKxtybwC1Xr/ccAZEarDE1U -4JtWoU9mU+vW0T5S14o3ZA4/TjfgHZaRO8bY0j97xx3KOBNgwBr/L2Bi845JWWwa -WIRbYiWQev4DhCjMEA8mxn9EVq7+sq4VmxY/OlajD/ppS9v8lM1CriD1YwETQAnl -+5bCLLsPejeJ0pIPC2sr5qqg6rJz3pGApakELdgCtPZQbFQQJfIO1EsCj7M4mdKR -OC8HNELS+5JPsW2PgSazVBkknaMUycDdzbgZmpEceRRPDeZK9MB05eb2OMXZ7gx1 -m2rWIQKCAQB6rpLk5l2CjR5YCBKsKavY3kzI3N8FRXKuLQjYAUHdR7iXVzLXiBss -v8XtFNTfASgI1BMmBTudp/qIiEg/upuI5Y4yELdoaY+Au80LMlKvp6QD/h3oxIL4 -p1PrRIO3+4SEitxKAWdKeKP9e1tyC2SeVrOrPkBhAtAqaC/U8kLCl1erdf7+BQjT -ybUarnTJoYbfSXbzp4iV95WoFzJXQScoGM+5eH/lfAqEmQjQyq0uaSZD/RPX9u3N -EXgbq5RWUWJaYztn7Eyvl4z7xY61eP15jotaIXFVjf8JKpVruCZRt+wO5xI1hXmu -4OAHqMEJgfDJ+OWeCydD233Su08mwfs1AoIBABnzt5VGd6K835vpZHsXiAxmCh5y -rk85wcnWy/Id1IpP91bDkHF/ilD/IpegS+dKGrmaEauKpRy+mRT+KyhUQAzS/Xnv -k/6wbbwzLFvmD3zm1pID4/LucetyyFQmM/45V+sDTNsf1sWA92we0n4q+MiR3Xep -apQoO90u3q2I811UlwfUzeLknnGr0+5FiQ2Lkt34GAgUr3ydNNw31fR9uWU4FRLq -JZNXYQcaeH7NoAW4bhS0fo3+KKl6Yqza8O4iu1v8wqbTgVuNd/OJSvYZSc76yDrc -Ghju++Rz9enWJfA00sTebHC+TDm97ASS6uZH2gwR6xjKggUbxlJ3uw/yQK4= ------END RSA PRIVATE KEY----- diff --git a/libs/libblade/test/ca/serial b/libs/libblade/test/ca/serial deleted file mode 100644 index dd11724042..0000000000 --- a/libs/libblade/test/ca/serial +++ /dev/null @@ -1 +0,0 @@ -1001 diff --git a/libs/libblade/test/ca/serial.old b/libs/libblade/test/ca/serial.old deleted file mode 100644 index 83b33d238d..0000000000 --- a/libs/libblade/test/ca/serial.old +++ /dev/null @@ -1 +0,0 @@ -1000 diff --git a/libs/libblade/test/nodeidgen.c b/libs/libblade/test/nodeidgen.c deleted file mode 100644 index 14f95d9336..0000000000 --- a/libs/libblade/test/nodeidgen.c +++ /dev/null @@ -1,16 +0,0 @@ -#include -#include -#include -#include - -int main() { - uint8_t nodeid[KS_DHT_NODEID_SIZE]; - char buf[KS_DHT_NODEID_SIZE * 2 + 1]; - - randombytes_buf(nodeid, KS_DHT_NODEID_SIZE); - - ks_dht_hex(nodeid, buf, KS_DHT_NODEID_SIZE); - - printf(buf); - return 0; -} diff --git a/libs/libblade/test/tap.c b/libs/libblade/test/tap.c deleted file mode 100644 index 152e39e8e0..0000000000 --- a/libs/libblade/test/tap.c +++ /dev/null @@ -1,354 +0,0 @@ -/* -libtap - Write tests in C -Copyright 2012 Jake Gelbman -This file is licensed under the LGPL -*/ - -#define _DEFAULT_SOURCE 1 - -#include -#include -#include -#include -#include "tap.h" - -static int expected_tests = NO_PLAN; -static int failed_tests; -static int current_test; -static char *todo_mesg; - -static char * -vstrdupf (const char *fmt, va_list args) { - char *str; - int size; - va_list args2; - va_copy(args2, args); - if (!fmt) - fmt = ""; - size = vsnprintf(NULL, 0, fmt, args2) + 2; - str = malloc(size); - if (!str) { - perror("malloc error"); - exit(1); - } - vsprintf(str, fmt, args); - va_end(args2); - return str; -} - -void -tap_plan (int tests, const char *fmt, ...) { - expected_tests = tests; - if (tests == SKIP_ALL) { - char *why; - va_list args; - va_start(args, fmt); - why = vstrdupf(fmt, args); - va_end(args); - printf("1..0 "); - diag("SKIP %s\n", why); - exit(0); - } - if (tests != NO_PLAN) { - printf("1..%d\n", tests); - } -} - -int -vok_at_loc (const char *file, int line, int test, const char *fmt, - va_list args) -{ - char *name = vstrdupf(fmt, args); - if (!test) { - printf("not "); - } - printf("ok %d", ++current_test); - if (*name) - printf(" - %s", name); - if (todo_mesg) { - printf(" # TODO"); - if (*todo_mesg) - printf(" %s", todo_mesg); - } - printf("\n"); - if (!test) { - printf("# Failed "); - if (todo_mesg) - printf("(TODO) "); - printf("test "); - if (*name) - printf("'%s'\n# ", name); - printf("at %s line %d.\n", file, line); - if (!todo_mesg) - failed_tests++; - } - free(name); - return test; -} - -int -ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - return test; -} - -static int -mystrcmp (const char *a, const char *b) { - return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); -} - -#define eq(a, b) (!mystrcmp(a, b)) -#define ne(a, b) (mystrcmp(a, b)) - -int -is_at_loc (const char *file, int line, const char *got, const char *expected, - const char *fmt, ...) -{ - int test = eq(got, expected); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" got: '%s'", got); - diag(" expected: '%s'", expected); - } - return test; -} - -int -isnt_at_loc (const char *file, int line, const char *got, const char *expected, - const char *fmt, ...) -{ - int test = ne(got, expected); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" got: '%s'", got); - diag(" expected: anything else"); - } - return test; -} - -int -cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, - const char *fmt, ...) -{ - int test = eq(op, "||") ? a || b - : eq(op, "&&") ? a && b - : eq(op, "|") ? a | b - : eq(op, "^") ? a ^ b - : eq(op, "&") ? a & b - : eq(op, "==") ? a == b - : eq(op, "!=") ? a != b - : eq(op, "<") ? a < b - : eq(op, ">") ? a > b - : eq(op, "<=") ? a <= b - : eq(op, ">=") ? a >= b - : eq(op, "<<") ? a << b - : eq(op, ">>") ? a >> b - : eq(op, "+") ? a + b - : eq(op, "-") ? a - b - : eq(op, "*") ? a * b - : eq(op, "/") ? a / b - : eq(op, "%") ? a % b - : diag("unrecognized operator '%s'", op); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" %d", a); - diag(" %s", op); - diag(" %d", b); - } - return test; -} - -static int -find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) { - size_t i; - if (a == b) - return 0; - if (!a || !b) - return 2; - for (i = 0; i < n; i++) { - if (a[i] != b[i]) { - *offset = i; - return 1; - } - } - return 0; -} - -int -cmp_mem_at_loc (const char *file, int line, const void *got, - const void *expected, size_t n, const char *fmt, ...) -{ - size_t offset; - int diff = find_mem_diff(got, expected, n, &offset); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, !diff, fmt, args); - va_end(args); - if (diff == 1) { - diag(" Difference starts at offset %d", offset); - diag(" got: 0x%02x", ((unsigned char *)got)[offset]); - diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]); - } - else if (diff == 2) { - diag(" got: %s", got ? "not NULL" : "NULL"); - diag(" expected: %s", expected ? "not NULL" : "NULL"); - } - return !diff; -} - -int -diag (const char *fmt, ...) { - va_list args; - char *mesg, *line; - int i; - va_start(args, fmt); - if (!fmt) - return 0; - mesg = vstrdupf(fmt, args); - line = mesg; - for (i = 0; *line; i++) { - char c = mesg[i]; - if (!c || c == '\n') { - mesg[i] = '\0'; - printf("# %s\n", line); - if (!c) - break; - mesg[i] = c; - line = mesg + i + 1; - } - } - free(mesg); - va_end(args); - return 0; -} - -int -exit_status () { - int retval = 0; - if (expected_tests == NO_PLAN) { - printf("1..%d\n", current_test); - } - else if (current_test != expected_tests) { - diag("Looks like you planned %d test%s but ran %d.", - expected_tests, expected_tests > 1 ? "s" : "", current_test); - retval = 2; - } - if (failed_tests) { - diag("Looks like you failed %d test%s of %d run.", - failed_tests, failed_tests > 1 ? "s" : "", current_test); - retval = 1; - } - return retval; -} - -int -bail_out (int ignore, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - printf("Bail out! "); - vprintf(fmt, args); - printf("\n"); - va_end(args); - exit(255); - return 0; -} - -void -tap_skip (int n, const char *fmt, ...) { - char *why; - va_list args; - va_start(args, fmt); - why = vstrdupf(fmt, args); - va_end(args); - while (n --> 0) { - printf("ok %d ", ++current_test); - diag("skip %s\n", why); - } - free(why); -} - -void -tap_todo (int ignore, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - todo_mesg = vstrdupf(fmt, args); - va_end(args); -} - -void -tap_end_todo () { - free(todo_mesg); - todo_mesg = NULL; -} - -#ifndef _WIN32 -#include -#include -#include - -#if defined __APPLE__ || defined BSD -#define MAP_ANONYMOUS MAP_ANON -#endif - -/* Create a shared memory int to keep track of whether a piece of code executed -dies. to be used in the dies_ok and lives_ok macros. */ -int -tap_test_died (int status) { - static int *test_died = NULL; - int prev; - if (!test_died) { - test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, -1, 0); - *test_died = 0; - } - prev = *test_died; - *test_died = status; - return prev; -} - -int -like_at_loc (int for_match, const char *file, int line, const char *got, - const char *expected, const char *fmt, ...) -{ - int test; - regex_t re; - va_list args; - int err = regcomp(&re, expected, REG_EXTENDED); - if (err) { - char errbuf[256]; - regerror(err, &re, errbuf, sizeof errbuf); - fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", - expected, errbuf, file, line); - exit(255); - } - err = regexec(&re, got, 0, NULL, 0); - regfree(&re); - test = for_match ? !err : err; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - if (for_match) { - diag(" '%s'", got); - diag(" doesn't match: '%s'", expected); - } - else { - diag(" '%s'", got); - diag(" matches: '%s'", expected); - } - } - return test; -} -#endif diff --git a/libs/libblade/test/tap.h b/libs/libblade/test/tap.h deleted file mode 100644 index 8269e7ead7..0000000000 --- a/libs/libblade/test/tap.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -libtap - Write tests in C -Copyright 2012 Jake Gelbman -This file is licensed under the LGPL -*/ - -#ifndef __TAP_H__ -#define __TAP_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef va_copy -#ifdef __va_copy -#define va_copy __va_copy -#else -#define va_copy(d, s) ((d) = (s)) -#endif -#endif - -#include -#include -#include - -int vok_at_loc (const char *file, int line, int test, const char *fmt, - va_list args); -int ok_at_loc (const char *file, int line, int test, const char *fmt, - ...); -int is_at_loc (const char *file, int line, const char *got, - const char *expected, const char *fmt, ...); -int isnt_at_loc (const char *file, int line, const char *got, - const char *expected, const char *fmt, ...); -int cmp_ok_at_loc (const char *file, int line, int a, const char *op, - int b, const char *fmt, ...); -int cmp_mem_at_loc (const char *file, int line, const void *got, - const void *expected, size_t n, const char *fmt, ...); -int bail_out (int ignore, const char *fmt, ...); -void tap_plan (int tests, const char *fmt, ...); -int diag (const char *fmt, ...); -int exit_status (void); -void tap_skip (int n, const char *fmt, ...); -void tap_todo (int ignore, const char *fmt, ...); -void tap_end_todo (void); - -#define NO_PLAN -1 -#define SKIP_ALL -2 -#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define cmp_mem(...) cmp_mem_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL); -#define plan(...) tap_plan(__VA_ARGS__, NULL) -#define done_testing() return exit_status() -#define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL) -#define pass(...) ok(1, "" __VA_ARGS__) -#define fail(...) ok(0, "" __VA_ARGS__) - -#define skip(test, ...) do {if (test) {tap_skip(__VA_ARGS__, NULL); break;} -#define end_skip } while (0) - -#define todo(...) tap_todo(0, "" __VA_ARGS__, NULL) -#define end_todo tap_end_todo() - -#define dies_ok(...) dies_ok_common(1, __VA_ARGS__) -#define lives_ok(...) dies_ok_common(0, __VA_ARGS__) - -#ifdef _WIN32 -#define like(...) tap_skip(1, "like is not implemented on Windows") -#define unlike tap_skip(1, "unlike is not implemented on Windows") -#define dies_ok_common(...) \ - tap_skip(1, "Death detection is not supported on Windows") -#else -#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) -#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) -int like_at_loc (int for_match, const char *file, int line, - const char *got, const char *expected, - const char *fmt, ...); -#include -#include -#include -int tap_test_died (int status); -#define dies_ok_common(for_death, code, ...) \ - do { \ - int cpid; \ - int it_died; \ - tap_test_died(1); \ - cpid = fork(); \ - switch (cpid) { \ - case -1: \ - perror("fork error"); \ - exit(1); \ - case 0: \ - close(1); \ - close(2); \ - code \ - tap_test_died(0); \ - exit(0); \ - } \ - if (waitpid(cpid, NULL, 0) < 0) { \ - perror("waitpid error"); \ - exit(1); \ - } \ - it_died = tap_test_died(0); \ - if (!it_died) \ - {code} \ - ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \ - } while (0) -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/libblade/test/testbuckets.c b/libs/libblade/test/testbuckets.c deleted file mode 100644 index c9eca0cc2d..0000000000 --- a/libs/libblade/test/testbuckets.c +++ /dev/null @@ -1,1293 +0,0 @@ -#pragma GCC diagnostic ignored "-Wunused-but-set-variable" -#pragma GCC diagnostic ignored "-Wunused-variable" -#pragma GCC diagnostic ignored "-Wunused-function" - -//#include "ks.h" -#include "../src/include/ks_dht.h" - -ks_dht_t *dht; -ks_dhtrt_routetable_t *rt; -ks_pool_t *pool; -ks_thread_pool_t *tpool; - - -static ks_thread_t *threads[10]; - -static char idbuffer[51]; - -static char *printableid(uint8_t *id) -{ - char *buffer = idbuffer; - memset(idbuffer, 0, sizeof(idbuffer)); - for (int i = 0; i < 20; ++i, buffer+=2) { - sprintf(buffer, "%02x", id[i]); - } - return idbuffer; -} - - - -int doquery(ks_dhtrt_routetable_t *rt, uint8_t *id, enum ks_dht_nodetype_t type, enum ks_afflags_t family) -{ - ks_dhtrt_querynodes_t query; - memset(&query, 0, sizeof(query)); - query.max = 30; - memcpy(&query.nodeid.id, id, KS_DHT_NODEID_SIZE); - query.family = family; - query.type = type; - - return ks_dhtrt_findclosest_nodes(rt, &query); -} - -void test01() -{ - printf("**** testbuckets - test01 start\n"); fflush(stdout); - - ks_dhtrt_routetable_t *rt; - ks_dhtrt_initroute(&rt, dht, pool); - ks_dhtrt_deinitroute(&rt); - - ks_dhtrt_initroute(&rt, dht, pool); - ks_dht_nodeid_t nodeid, homeid; - memset(homeid.id, 0xdd, KS_DHT_NODEID_SIZE); - homeid.id[19] = 0; - - char ip[] = "192.168.100.100"; - unsigned short port = 7000; - ks_dht_node_t *peer; - ks_dht_node_t *peer1; - - ks_status_t status; - status = ks_dhtrt_create_node(rt, homeid, KS_DHT_LOCAL, ip, port, KS_DHTRT_CREATE_DEFAULT, &peer); - if (status == KS_STATUS_FAIL) { - printf("* **ks_dhtrt_create_node test01 failed\n"); - exit(101); - } - - peer = ks_dhtrt_find_node(rt, homeid); - if (peer != 0) { - printf("*** ks_dhtrt_find_node test01 failed. find should fail\n"); fflush(stdout); - exit(102); - } - - ks_dhtrt_touch_node(rt, homeid); - - peer = ks_dhtrt_find_node(rt, homeid); - if (peer == 0) { - printf("*** ks_dhtrt_find_node test01 failed. find should succeed\n"); fflush(stdout); - exit(102); - } - - status = ks_dhtrt_create_node(rt, homeid, KS_DHT_LOCAL, ip, port, KS_DHTRT_CREATE_DEFAULT, &peer1); - if (status == KS_STATUS_FAIL) { - printf("**** ks_dhtrt_create_node test01 did not allow duplicate createnodes!!\n"); - exit(103); - } - if (peer != peer1) { - printf("**** ks_dhtrt_create_node duplicate createnode did not return the same node!\n"); - exit(104); - } - - status = ks_dhtrt_delete_node(rt, peer); - if (status == KS_STATUS_FAIL) { - printf("**** ks_dhtrt_delete_node test01 failed\n"); - exit(104); - } - - /* test create_node flags */ - /* ---------------------- */ - - memset(homeid.id, 0xab, KS_DHT_NODEID_SIZE); - status = ks_dhtrt_create_node(rt, homeid, KS_DHT_LOCAL, ip, port, KS_DHTRT_CREATE_PING, &peer); - - peer = ks_dhtrt_find_node(rt, homeid); - if (peer != 0) { - printf("*** ks_dhtrt_find_node test01 failed. find@2 should fail\n"); fflush(stdout); - exit(106); - } - - status = ks_dhtrt_create_node(rt, homeid, KS_DHT_LOCAL, ip, port, KS_DHTRT_CREATE_TOUCH, &peer); - peer1 = ks_dhtrt_find_node(rt, homeid); - if (peer1 == 0) { - printf("*** ks_dhtrt_find_node test01 failed. find@3 should succeed after create w/touch\n"); fflush(stdout); - exit(106); - } - if (peer1 != peer) { - printf("*** peer != peer1 @4 - both creates should return the same node\n"); fflush(stdout); - exit(107); - } - - /* ok now delete both and see what happens */ - ks_dhtrt_delete_node(rt, peer); - ks_dhtrt_delete_node(rt, peer1); - - memset(nodeid.id, 0xab, KS_DHT_NODEID_SIZE); - status = ks_dhtrt_create_node(rt, homeid, KS_DHT_LOCAL, ip, port, KS_DHTRT_CREATE_TOUCH, &peer); - - peer = ks_dhtrt_find_node(rt, nodeid); - if (peer == 0) { - printf("*** ks_dhtrt_find_node test01 failed. find@5 should succeed after create_node w/touch\n"); fflush(stdout); - exit(108); - } - - ks_dhtrt_delete_node(rt, peer); - - printf("**** testbuckets - test01 complete\n\n\n"); fflush(stdout); -} - -void test02() -{ - printf("**** testbuckets - test02 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - ks_dht_nodeid_t nodeid; - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - enum ks_afflags_t both = ifboth; - - ks_status_t status; - - nodeid.id[0] = 1; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_LOCAL, ipv6, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[0] = 2; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv6, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[0] = 3; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv6, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[0] = 4; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_LOCAL, ipv6, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[1] = 1; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv6, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - - - nodeid.id[19] = 1; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[19] = 2; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[19] = 3; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[19] = 4; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_LOCAL, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - - nodeid.id[19] = 5; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - nodeid.id[19] = 6; - status = ks_dhtrt_create_node(rt, nodeid, KS_DHT_LOCAL, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - - int qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, both); - printf("\n* **local query count expected 3, actual %d\n", qcount); fflush(stdout); - qcount = doquery(rt, nodeid.id, KS_DHT_REMOTE, both); - printf("\n* **remote query count expected 6, actual %d\n", qcount); fflush(stdout); - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, both); - printf("\n* **both query count expected 9, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, ifv4); - printf("\n* **local AF_INET query count expected 1, actual %d\n", qcount); fflush(stdout); - qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, ifv6); - printf("\n* **local AF_INET6 query count expected 2, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, ifv6); - printf("\n* **AF_INET6 count expected 5, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_REMOTE, ifv4); - printf("\n* **remote AF_INET query count expected 3, actual %d\n", qcount); fflush(stdout); - qcount = doquery(rt, nodeid.id, KS_DHT_REMOTE, ifv6); - printf("\n* **remote AF_INET6 query count expected 3, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, ifv4); - printf("\n* **AF_INET count expected 4, actual %d\n", qcount); fflush(stdout); - - nodeid.id[19] = 5; - ks_dhtrt_touch_node(rt, nodeid); - nodeid.id[19] = 6; - ks_dhtrt_touch_node(rt, nodeid); - - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, ifv4); - printf("\n**** AF_INET (after touch) count expected 6, actual %d\n", qcount); fflush(stdout); - - printf("**** testbuckets - test02 finished\n"); fflush(stdout); - - return; -} - -/* this is similar to test2 but after mutiple table splits. */ - -void test03() -{ - printf("**** testbuckets - test03 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - ks_dht_nodeid_t nodeid; - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - enum ks_afflags_t both = ifboth; - - ks_status_t status; - int ipv4_remote = 0; - int ipv4_local = 0; - - int cix=0; - - for (int i=0; i<200; ++i) { - if (i%20 == 0) { - nodeid.id[cix] >>= 1; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_status_t s0 = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - if (s0 == KS_STATUS_SUCCESS) { - ks_dhtrt_touch_node(rt, nodeid); - ++ipv4_remote; - } - } - - for (int i=0; i<2; ++i) { - if (i%20 == 0) { - nodeid.id[cix] >>= 1; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_status_t s0 = ks_dhtrt_create_node(rt, nodeid, KS_DHT_LOCAL, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - if (s0 == KS_STATUS_SUCCESS) { - ks_dhtrt_touch_node(rt, nodeid); - ++ipv4_remote; - } - } - - for (int i=0; i<200; ++i) { - if (i%20 == 0) { - nodeid.id[cix] >>= 1; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_status_t s0 = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv6, port, KS_DHTRT_CREATE_DEFAULT, &peer); - if (s0 == KS_STATUS_SUCCESS) { - ks_dhtrt_touch_node(rt, nodeid); - ++ipv4_remote; - } - } - - ks_dhtrt_dump(rt, 7); - - - int qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, both); - printf("\n**** local query count expected 2, actual %d, max %d\n", qcount, ipv4_local); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_REMOTE, both); - printf("\n**** remote query count expected 20, actual %d\n", qcount); fflush(stdout); - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, both); - printf("\n**** both query count expected 20, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, ifv4); - printf("\n**** local AF_INET query count expected 2, actual %d\n", qcount); fflush(stdout); - qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, ifv6); - printf("\n**** local AF_INET6 query count expected 0, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, ifv6); - printf("\n**** AF_INET6 count expected 20, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_REMOTE, ifv4); - printf("\n**** remote AF_INET query count expected 20, actual %d max %d\n", qcount, ipv4_remote); fflush(stdout); - qcount = doquery(rt, nodeid.id, KS_DHT_REMOTE, ifv6); - printf("\n**** remote AF_INET6 query count expected 20, actual %d\n", qcount); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, ifv4); - printf("\n**** AF_INET count expected 20, actual %d\n", qcount); fflush(stdout); - - printf("**** testbuckets - test03 finished\n\n\n"); fflush(stdout); - return; -} - -void test04() -{ - printf("**** testbuckets - test04 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - ks_dht_nodeid_t nodeid; - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - enum ks_afflags_t both = ifboth; - - ks_status_t status; - - for (int i=0,i2=0,i3=0; i<10000; ++i, ++i2, ++i3) { - if (i%20 == 0) { - nodeid.id[0] = nodeid.id[0] / 2; - if (i2%20 == 0) { - nodeid.id[1] = nodeid.id[1] / 2; - i2 = 0; - if (i3%20 == 0) { - nodeid.id[2] = nodeid.id[2] / 2; - } - } - else { - ++nodeid.id[3]; - } - } - else { - ++nodeid.id[1]; - } - ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - } - - - memset(nodeid.id, 0x2f, KS_DHT_NODEID_SIZE); - ks_time_t t0 = ks_time_now(); - int qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, ifv4); - ks_time_t t1 = ks_time_now(); - - int tx = t1 - t0; - t1 /= 1000; - - printf("**** query on 10k nodes in %d ms\n", tx); - - printf("**** testbuckets - test04 finished\n\n\n"); fflush(stdout); - - return; -} - -/* test read/write node locking */ -void test05() -{ - printf("**** testbuckets - test05 start\n"); fflush(stdout); - - ks_dht_node_t *peer, *peer1, *peer2; - ks_dht_nodeid_t nodeid; - ks_status_t s; - - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7001; - - ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - - peer1 = ks_dhtrt_find_node(rt, nodeid); - printf("test05 - first find compelete\n"); fflush(stdout); - - peer2 = ks_dhtrt_find_node(rt, nodeid); - printf("test05 - second find compelete\n"); fflush(stdout); - - ks_dhtrt_delete_node(rt, peer); - printf("test05 - delete compelete\n"); fflush(stdout); - - s = ks_dhtrt_release_node(peer1); - if (s == KS_STATUS_FAIL) printf("release 1 failed\n"); fflush(stdout); - - s = ks_dhtrt_release_node(peer2); - if (s == KS_STATUS_FAIL) printf("release 1 failed\n"); - - s = ks_dhtrt_release_node(peer2); - if (s == KS_STATUS_FAIL) printf("release 1 failed\n"); - - - printf("* **testbuckets - test05 finished\n\n\n"); fflush(stdout); - - return; -} - - -/* test06 */ -/* ------ */ -ks_dht_nodeid_t g_nodeid1; -ks_dht_nodeid_t g_nodeid2; -ks_dht_node_t *g_peer; - -static void *testnodelocking_ex1(ks_thread_t *thread, void *data) -{ - //lock=3 on entry - ks_dhtrt_release_node(g_peer); //lock=2 - ks_dhtrt_release_node(g_peer); //lock=1 - ks_dhtrt_release_node(g_peer); //lock=0 - return NULL; -} - -static void *testnodelocking_ex2(ks_thread_t *thread, void *data) -{ - // lock=4 on entry - ks_dht_node_t *peer2 = ks_dhtrt_find_node(rt, g_nodeid1); //lock=5 - ks_dhtrt_release_node(peer2); //lock=4 - ks_dhtrt_sharelock_node(peer2); //lock=5 - ks_dhtrt_release_node(peer2); //lock=4 - ks_dhtrt_sharelock_node(peer2); //lock=5 - ks_dhtrt_release_node(peer2); //lock=4 - ks_dhtrt_release_node(peer2); //lock=3 - ks_dhtrt_find_node(rt, g_nodeid1); //lock=4 - ks_dhtrt_release_node(peer2); //lock=3 - - return NULL; -} - - -void test06() -{ - printf("**** testbuckets - test06 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - memset(g_nodeid1.id, 0xef, KS_DHT_NODEID_SIZE); - memset(g_nodeid2.id, 0x1f, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - - ks_dhtrt_create_node(rt, g_nodeid1, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); // lock=1 - ks_dhtrt_touch_node(rt, g_nodeid1); - - ks_dht_node_t *peer2 = ks_dhtrt_find_node(rt, g_nodeid1); //lock=2 - peer2 = ks_dhtrt_find_node(rt, g_nodeid1); //lock=3 - peer2 = ks_dhtrt_find_node(rt, g_nodeid1); //lock=4 - - ks_dhtrt_release_node(peer2); //lock=3 - ks_dhtrt_sharelock_node(peer2); //lock=4 - - g_peer = peer2; - - ks_thread_t *t0; - ks_thread_create(&t0, testnodelocking_ex1, NULL, pool); - - ks_thread_t *t1; - ks_thread_create(&t1, testnodelocking_ex2, NULL, pool); - - ks_thread_join(t1); - ks_thread_join(t0); - - ks_dhtrt_delete_node(rt, peer2); - - printf("\n\n* **testbuckets - test06 -- check if the node gets deleted\n\n\n\n"); fflush(stdout); - - ks_dhtrt_process_table(rt); - - printf("**** testbuckets - test06 start\n"); fflush(stdout); - - return; -} - -void test07() -{ - printf("**** testbuckets - test07 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - memset(g_nodeid1.id, 0xef, KS_DHT_NODEID_SIZE); - memset(g_nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - - /* build a delete queue */ - - int cix=0; - - for(int i0=0, i1=0; i0<150; ++i0, ++i1) { - if (i0%20 == 0) { - g_nodeid2.id[cix]>>=1; - //ks_dhtrt_dump(rt, 7); - if ( g_nodeid2.id[cix] == 0) ++cix; - g_nodeid2.id[19] = 0; - } - else { - ++g_nodeid2.id[19]; - } - ks_dhtrt_create_node(rt, g_nodeid2, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, g_nodeid2); - ks_dhtrt_release_node(peer); - } - - ks_dhtrt_dump(rt, 7); - cix = 0; - - memset(g_nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - for (int i0=0, i1=0; i0<150; ++i0, ++i1) { - if (i0%20 == 0) { - g_nodeid2.id[cix]>>=1; - if ( g_nodeid2.id[cix] == 0) ++cix; - g_nodeid2.id[19] = 0; - } - else { - ++g_nodeid2.id[19]; - } - ks_dht_node_t* n = ks_dhtrt_find_node(rt, g_nodeid2); - ks_dhtrt_release_node(n); - ks_dhtrt_delete_node(rt, n); - } - - ks_dhtrt_process_table(rt); - - printf("**** test07 should delete 100 nodes, leaving 50\n"); fflush(stdout); - printf("**** testbuckets - test07 ended\n"); fflush(stdout); -} - - -void test08() -{ - printf("**** testbuckets - test08 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - memset(g_nodeid1.id, 0xef, KS_DHT_NODEID_SIZE); - memset(g_nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - - /* build a delete queue */ - - int cix=0; - - for(int i0=0, i1=0; i0<150; ++i0, ++i1) { - if (i0%20 == 0) { - g_nodeid2.id[cix]>>=1; - //ks_dhtrt_dump(rt, 7); - if ( g_nodeid2.id[cix] == 0) ++cix; - g_nodeid2.id[19] = 0; - } - else { - ++g_nodeid2.id[19]; - } - ks_dhtrt_create_node(rt, g_nodeid2, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, g_nodeid2); - ks_dhtrt_release_node(peer); - } - - cix = 0; - - memset(g_nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - for (int i0=0, i1=0; i0<150; ++i0, ++i1) { - if (i0%20 == 0) { - g_nodeid2.id[cix]>>=1; - if ( g_nodeid2.id[cix] == 0) ++cix; - g_nodeid2.id[19] = 0; - } - else { - ++g_nodeid2.id[19]; - } - ks_dht_node_t* n = ks_dhtrt_find_node(rt, g_nodeid2); - ks_dhtrt_release_node(n); - ks_dhtrt_delete_node(rt, n); - } - - /* this should drive the search_findnode */ - - for(int i=0; i<45; ++i) { - printf("firing process table\n"); - ks_dhtrt_process_table(rt); - ks_sleep(1000 * 1000 * 60); /* sleep one minutes */ - } - - printf("**** testbuckets - test08 ended\n"); fflush(stdout); -} - - -void test09() -{ - printf("**** testbuckets - test09 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - memset(g_nodeid1.id, 0xef, KS_DHT_NODEID_SIZE); - memset(g_nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - - int cix=0; - - for(int i0=0, i1=0; i0<150; ++i0, ++i1) { - if (i0%20 == 0) { - g_nodeid2.id[cix]>>=1; - //ks_dhtrt_dump(rt, 7); - if ( g_nodeid2.id[cix] == 0) ++cix; - g_nodeid2.id[19] = 0; - } - else { - ++g_nodeid2.id[19]; - } - ks_dhtrt_create_node(rt, g_nodeid2, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, g_nodeid2); - ks_dhtrt_release_node(peer); - } - - /* this should expire all nodes after 15 minutes and 3 pings */ - - printf("\n\n\n\n"); - - for(int i=0; i<45; ++i) { - printf("firing process table\n"); - ks_dhtrt_process_table(rt); - ks_sleep(1000 * 1000 * 30); /* sleep 30 seconds */ - } - - printf("**** testbuckets - test09 ended\n"); fflush(stdout); -} - - - - -typedef struct ks_dhtrt_serialized_routetable_s -{ - uint32_t size; - uint8_t version; - uint8_t count; - char eye[4]; -} ks_dhtrt_serialized_routetable_t; - - -void test10() -{ - printf("**** testbuckets - test10 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - memset(g_nodeid1.id, 0xef, KS_DHT_NODEID_SIZE); - memset(g_nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - - int cix=0; - - for(int i0=0, i1=0; i0<2500; ++i0, ++i1) { - if (i0%20 == 0) { - g_nodeid2.id[cix]>>=1; - //ks_dhtrt_dump(rt, 7); - if ( g_nodeid2.id[cix] == 0) ++cix; - g_nodeid2.id[19] = 0; - } - else { - ++g_nodeid2.id[19]; - } - ks_dhtrt_create_node(rt, g_nodeid2, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, g_nodeid2); - ks_dhtrt_release_node(peer); - } - - /* this should expire all nodes after 15 minutes and 3 pings */ - void *buffer = NULL; - uint32_t size = ks_dhtrt_serialize(rt, &buffer); - - - if (size > 0) { - ks_dhtrt_serialized_routetable_t* p = (ks_dhtrt_serialized_routetable_t*)buffer; - printf("\n\ntest10: version %d bucket count %d size %d\n\n", p->version, p->count, p->size); - ks_dhtrt_dump(rt, 7); - } - else { - printf("test10: error on serialize\n"); - return; - } - - - ks_dhtrt_routetable_t* rt2; - ks_dhtrt_initroute(&rt2, dht, pool); - ks_dhtrt_deserialize(rt2, buffer); - ks_dhtrt_dump(rt2, 7); - - ks_dht_nodeid_t id; - memset(id.id, 0xef, 20); - id.id[0] = 0x0e; - id.id[19] = 0x05; - - ks_dhtrt_touch_node(rt2, id); - ks_dht_node_t* n = ks_dhtrt_find_node(rt2, id); - - if (n == NULL) { - printf("test10: failed Unable to find reloaded node \n"); - exit(200); - } - - - ks_dhtrt_deinitroute(&rt2); - - printf("test10: complete\n"); - - return; - -} - - - - - - -static int gindex = 1; -static ks_mutex_t *glock; -static int gstop = 0; - -static int test60loops = 1000; -static int test60nodes = 200; /* max at 255 */ - -static void *test60ex1(ks_thread_t *thread, void *data) -{ - while(!gstop) { - ks_dhtrt_process_table(rt); - ks_sleep(100); - } - return NULL; -} - - -static void *test60ex2(ks_thread_t *thread, void *data) -{ - ks_dht_nodeid_t nodeid; - ks_dhtrt_querynodes_t query; - - - while(!gstop) { - - memset(&query, 0, sizeof(query)); - memset(query.nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - query.max = 30; - query.family = ifv4; - query.type = KS_DHT_REMOTE; - - - ks_dhtrt_findclosest_nodes(rt, &query); - ks_sleep(10000); - - for (int i=0; i>= 1; - if (nodeid.id[cix] == 0) { - ++cix; - } - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_dhtrt_create_node(rt, nodeid, KS_DHT_LOCAL, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_sleep(1000); - ks_dhtrt_touch_node(rt, nodeid); - } - - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - cix = 0; - - for (int i=0, cix=0; i>= 1; - if (nodeid.id[cix] == 0) { - ++cix; - } - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - - peer = ks_dhtrt_find_node(rt, nodeid); - if (peer) { - ks_dhtrt_delete_node(rt, peer); - ks_sleep(400); - } - } - - } - - return 0; - -} - -void test60() -{ - printf("**** test60: starting\n"); fflush(stdout); - int i; - ks_mutex_create(&glock, KS_MUTEX_FLAG_DEFAULT, pool); - - ks_thread_t *t0; - ks_thread_create(&t0, test60ex1, NULL, pool); - - ks_thread_t *t1; - ks_thread_create(&t1, test60ex2, NULL, pool); - - for (i = 0; i < 10; i++) { - ks_thread_create(&threads[i], test60ex, &i, pool); - } - - printf("all threads started\n"); fflush(stdout); - - for (i = 0; i < 10; i++) { - ks_thread_join(threads[i]); - } - gstop = 1; - - ks_thread_join(t1); - - ks_thread_join(t0); - - printf("all threads completed\n"); fflush(stdout); - ks_dhtrt_dump(rt, 7); - printf("**** test60: completed\n"); fflush(stdout); - - - return; -} - - -void test30() -{ - printf("**** testbuckets - test03 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - ks_dht_nodeid_t nodeid; - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - enum ks_afflags_t both = ifboth; - - ks_status_t status; - int ipv4_remote = 0; - int ipv4_local = 0; - - int cix =0; - - for (int i=0; i<200; ++i) { - if (i%10 == 0) { - ++nodeid.id[cix]; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_status_t s0 = ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - if (s0 == KS_STATUS_SUCCESS) { - ks_dhtrt_touch_node(rt, nodeid); - ++ipv4_remote; - } - } - - for (int i=0; i<2; ++i) { - if (i%10 == 0) { - ++nodeid.id[cix]; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - - ks_status_t s0 = ks_dhtrt_create_node(rt, nodeid, KS_DHT_LOCAL, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - if (s0 == KS_STATUS_SUCCESS) { - ks_dhtrt_touch_node(rt, nodeid); - ++ipv4_local; - } - } - - for (int i=0; i<201; ++i) { - if (i%10 == 0) { - ++nodeid.id[cix]; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv6, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - } - - - ks_dhtrt_dump(rt, 7); - - - int qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, both); - printf("\n **** local query count expected 2, actual %d, max %d\n", qcount, ipv4_local); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_LOCAL, both); - printf("\n **** local query count expected 2, actual %d, max %d\n", qcount, ipv4_local); fflush(stdout); - - qcount = doquery(rt, nodeid.id, KS_DHT_BOTH, both); - printf("\n **** local query count expected 20, actual %d, max %d\n", qcount, ipv4_local); fflush(stdout); - - return; -} - - - - - - - -/* test resue of node memory */ -void test50() -{ - printf("*** testbuckets - test50 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - ks_dht_nodeid_t nodeid, nodeid2; - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - memset(nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - enum ks_afflags_t both = ifboth; - - ks_status_t status; - - int cix=0; - - for (int i=0,i2=0; i<200; ++i, ++i2) { - if (i%20 == 0) { - nodeid.id[cix] = nodeid.id[cix] / 2; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - } - - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - cix = 0; - - for (int i=0,i2=0; i<200; ++i, ++i2) { - if (i%20 == 0) { - nodeid.id[0] = nodeid.id[0] / 2; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_dht_node_t *n = ks_dhtrt_find_node(rt, nodeid); - if (n != NULL) { - ks_dhtrt_release_node(n); - ks_dhtrt_delete_node(rt, n); - } - } - - ks_dhtrt_process_table(rt); - - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - cix = 0; - - for (int i=0,i2=0; i<200; ++i, ++i2) { - if (i%20 == 0) { - nodeid.id[0] = nodeid.id[0] / 2; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - - ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - } - - printf("**** testbuckets - test50 start\n"); fflush(stdout); - return; -} - - -/* test process_table */ -void test51() -{ - printf("**** testbuckets - test51 start\n"); fflush(stdout); - - ks_dht_node_t *peer; - ks_dht_nodeid_t nodeid, nodeid2; - memset(nodeid.id, 0xef, KS_DHT_NODEID_SIZE); - memset(nodeid2.id, 0xef, KS_DHT_NODEID_SIZE); - - char ipv6[] = "1234:1234:1234:1234"; - char ipv4[] = "123.123.123.123"; - unsigned short port = 7000; - enum ks_afflags_t both = ifboth; - - ks_status_t status; - - int cix =0; - - for (int i=0,i2=0; i<2; ++i, ++i2) { - if (i%20 == 0) { - nodeid.id[0] = nodeid.id[0] / 2; - if (nodeid.id[cix] == 0) ++cix; - nodeid.id[19] = 0; - } - else { - ++nodeid.id[19]; - } - ks_dhtrt_create_node(rt, nodeid, KS_DHT_REMOTE, ipv4, port, KS_DHTRT_CREATE_DEFAULT, &peer); - ks_dhtrt_touch_node(rt, nodeid); - } - - for (int ix=0; ix<50; ++ix) { - ks_dhtrt_process_table(rt); - ks_sleep(1000 *1000 *120); - printf("* **pulse ks_dhtrt_process_table\n"); - if ( ix%2 == 0) ks_dhtrt_dump(rt, 7); - } - - printf("**** testbuckets - test51 complete\n"); fflush(stdout); - - return; -} - - -void testid(int max) { - - int cix=0; - unsigned char id[20]; - - memset(id, 0xff, 20); - - for (int i=0; i>= 1; - if (id[cix] == 0) { - ++cix; - } - id[19] = 0; - } - else { - ++id[19]; - } - printf("id:%s\n", printableid(id)); - } - -} - - - - - -int main(int argc, char *argv[]) { - - printf("testdhtbuckets - start\n"); - - int tests[100]; - if (argc == 0) { - tests[0] = 1; - tests[1] = 2; - tests[2] = 3; - tests[3] = 4; - tests[4] = 5; - } - else { - for(int tix=1; tix<100 && tixtype == cJSON_String) { - nodeid = elem->valuestring; - } - } - } - - blade_session_read_unlock(bs); - - if (nodeid) { - if (g_testcon_nodeid) ks_pool_free(&g_testcon_nodeid); - g_testcon_nodeid = ks_pstrdup(ks_pool_get(bh), nodeid); - } - - ks_log(KS_LOG_DEBUG, "Session (%s) locate (%s) provider (%s)\n", blade_session_id_get(bs), res_result_protocol, g_testcon_nodeid); - - return KS_FALSE; -} - -ks_bool_t test_join_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *result = NULL; - - ks_assert(brpcres); - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - result = blade_rpcexecute_response_result_get(brpcres); - ks_assert(result); - - ks_log(KS_LOG_DEBUG, "Session (%s) test.join response processing\n", blade_session_id_get(bs)); - - blade_session_read_unlock(bs); - - return KS_FALSE; -} - -ks_bool_t test_leave_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *result = NULL; - - ks_assert(brpcres); - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - result = blade_rpcexecute_response_result_get(brpcres); - ks_assert(result); - - ks_log(KS_LOG_DEBUG, "Session (%s) test.leave response processing\n", blade_session_id_get(bs)); - - blade_session_read_unlock(bs); - - return KS_FALSE; -} - -ks_bool_t test_talk_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *result = NULL; - - ks_assert(brpcres); - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - result = blade_rpcexecute_response_result_get(brpcres); - ks_assert(result); - - ks_log(KS_LOG_DEBUG, "Session (%s) test.talk response processing\n", blade_session_id_get(bs)); - - blade_session_read_unlock(bs); - - return KS_FALSE; -} - -ks_bool_t test_subscribe_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *res = NULL; - cJSON *res_result = NULL; - - ks_assert(brpcres); - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - res = blade_rpc_response_message_get(brpcres); - ks_assert(res); - - res_result = cJSON_GetObjectItem(res, "result"); - ks_assert(res_result); - - ks_log(KS_LOG_DEBUG, "Session (%s) blade.subscribe response processing\n", blade_session_id_get(bs)); - - blade_session_read_unlock(bs); - - return KS_FALSE; -} - -ks_bool_t test_channel_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - cJSON *params = NULL; - //cJSON *result = NULL; - - ks_assert(brpcreq); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - params = blade_rpcbroadcast_request_params_get(brpcreq); - ks_assert(params); - - ks_log(KS_LOG_DEBUG, "Session (%s) test channel event processing\n", blade_session_id_get(bs)); - - blade_session_read_unlock(bs); - - return KS_FALSE; -} - - -int main(int argc, char **argv) -{ - blade_handle_t *bh = NULL; - config_t config; - config_setting_t *config_blade = NULL; - const char *cfgpath = "testcli.cfg"; - //const char *session_state_callback_id = NULL; - const char *autoconnect = NULL; - - ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG); - - blade_init(); - - blade_handle_create(&bh); - - //if (argc > 1) cfgpath = argv[1]; - if (argc > 1) autoconnect = argv[1]; - - config_init(&config); - if (!config_read_file(&config, cfgpath)) { - ks_log(KS_LOG_ERROR, "%s:%d - %s\n", config_error_file(&config), config_error_line(&config), config_error_text(&config)); - config_destroy(&config); - return EXIT_FAILURE; - } - config_blade = config_lookup(&config, "blade"); - if (!config_blade) { - ks_log(KS_LOG_ERROR, "Missing 'blade' config group\n"); - config_destroy(&config); - return EXIT_FAILURE; - } - if (config_setting_type(config_blade) != CONFIG_TYPE_GROUP) { - ks_log(KS_LOG_ERROR, "The 'blade' config setting is not a group\n"); - return EXIT_FAILURE; - } - - if (blade_handle_startup(bh, config_blade) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_ERROR, "Blade startup failed\n"); - return EXIT_FAILURE; - } - - if (autoconnect) { - blade_connection_t *bc = NULL; - blade_identity_t *target = NULL; - ks_bool_t connected = KS_FALSE; - - blade_identity_create(&target, ks_pool_get(bh)); - - if (blade_identity_parse(target, autoconnect) == KS_STATUS_SUCCESS) connected = blade_handle_connect(bh, &bc, target, NULL) == KS_STATUS_SUCCESS; - - blade_identity_destroy(&target); - - - if (connected) { - // @todo use session state change callback to know when the session is ready after blade.connect - ks_sleep_ms(3000); - } - } - - loop(bh); - - blade_handle_destroy(&bh); - - config_destroy(&config); - - blade_shutdown(); - - return 0; -} - -void loop(blade_handle_t *bh) -{ - char buf[CONSOLE_INPUT_MAX]; - while (!g_shutdown) { - if (!fgets(buf, CONSOLE_INPUT_MAX, stdin)) break; - - for (int index = 0; buf[index]; ++index) { - if (buf[index] == '\r' || buf[index] == '\n') { - buf[index] = '\0'; - break; - } - } - process_console_input(bh, buf); - } -} - -void parse_argument(char **input, char **arg, char terminator) -{ - char *tmp; - - ks_assert(input); - ks_assert(*input); - ks_assert(arg); - - tmp = *input; - *arg = tmp; - - while (*tmp && *tmp != terminator) ++tmp; - if (*tmp == terminator) { - *tmp = '\0'; - ++tmp; - } - *input = tmp; -} - -void process_console_input(blade_handle_t *bh, char *line) -{ - char *args = line; - char *cmd = NULL; - ks_bool_t found = KS_FALSE; - - parse_argument(&args, &cmd, ' '); - - ks_log(KS_LOG_DEBUG, "Command: %s, Args: %s\n", cmd, args); - - for (int32_t index = 0; command_defs[index].cmd; ++index) { - if (!strcmp(command_defs[index].cmd, cmd)) { - found = KS_TRUE; - command_defs[index].callback(bh, args); - } - } - if (!found) ks_log(KS_LOG_INFO, "Command '%s' unknown.\n", cmd); -} - -void command_quit(blade_handle_t *bh, char *args) -{ - //ks_assert(bh); - ks_assert(args); - - g_shutdown = KS_TRUE; -} - -void command_locate(blade_handle_t *bh, char *args) -{ - ks_assert(bh); - ks_assert(args); - - blade_handle_rpclocate(bh, "test", test_locate_response_handler, NULL); -} - -void command_join(blade_handle_t *bh, char *args) -{ - cJSON *params = NULL; - - ks_assert(bh); - ks_assert(args); - - if (!g_testcon_nodeid) { - ks_log(KS_LOG_DEBUG, "Protocol controller has not been located\n"); - return; - } - - params = cJSON_CreateObject(); - blade_handle_rpcexecute(bh, g_testcon_nodeid, "test.join", "test", params, 0, test_join_response_handler, NULL); - cJSON_Delete(params); -} - -void command_subscribe(blade_handle_t *bh, char *args) -{ - cJSON *channels = NULL; - - if (!g_testcon_nodeid) { - ks_log(KS_LOG_DEBUG, "Protocol controller has not been located\n"); - return; - } - - channels = cJSON_CreateArray(); - cJSON_AddItemToArray(channels, cJSON_CreateString("channel")); - if (args && args[0]) cJSON_AddItemToArray(channels, cJSON_CreateString(args)); - blade_handle_rpcsubscribe(bh, BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_ADD, "test", channels, NULL, NULL, test_channel_handler, NULL); - cJSON_Delete(channels); -} - -void command_unsubscribe(blade_handle_t *bh, char *args) -{ - cJSON *channels = NULL; - - if (!g_testcon_nodeid) { - ks_log(KS_LOG_DEBUG, "Protocol controller has not been located\n"); - return; - } - - channels = cJSON_CreateArray(); - cJSON_AddItemToArray(channels, cJSON_CreateString("channel")); - if (args && args[0]) cJSON_AddItemToArray(channels, cJSON_CreateString(args)); - blade_handle_rpcsubscribe(bh, BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_REMOVE, "test", channels, test_subscribe_response_handler, NULL, test_channel_handler, NULL); - cJSON_Delete(channels); -} - -void command_leave(blade_handle_t *bh, char *args) -{ - cJSON *params = NULL; - - ks_assert(bh); - ks_assert(args); - - if (!g_testcon_nodeid) { - ks_log(KS_LOG_DEBUG, "Protocol controller has not been located\n"); - return; - } - - params = cJSON_CreateObject(); - blade_handle_rpcexecute(bh, g_testcon_nodeid, "test.leave", "test", params, 0, test_leave_response_handler, NULL); - cJSON_Delete(params); -} - -void command_talk(blade_handle_t *bh, char *args) -{ - cJSON *params = NULL; - - ks_assert(bh); - ks_assert(args); - - if (!g_testcon_nodeid) { - ks_log(KS_LOG_DEBUG, "Protocol controller has not been located\n"); - return; - } - if (!args[0]) { - ks_log(KS_LOG_DEBUG, "Syntax: talk \n"); - return; - } - - params = cJSON_CreateObject(); - cJSON_AddStringToObject(params, "text", args); - //blade_handle_rpcexecute(bh, g_testcon_nodeid, "test.talk", "test", params, test_talk_response_handler, NULL); - blade_handle_rpcexecute(bh, "blade:testcon@freeswitch.com", "test.talk", "test", params, 0, test_talk_response_handler, NULL); - cJSON_Delete(params); -} - -/* For Emacs: -* Local Variables: -* mode:c -* indent-tabs-mode:t -* tab-width:4 -* c-basic-offset:4 -* End: -* For VIM: -* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: -*/ diff --git a/libs/libblade/test/testcli.cfg b/libs/libblade/test/testcli.cfg deleted file mode 100644 index 2315c2456d..0000000000 --- a/libs/libblade/test/testcli.cfg +++ /dev/null @@ -1,15 +0,0 @@ -blade: -{ - transport: - { - wss: - { - ssl: - { - key = "./ca/intermediate/private/client@freeswitch-upstream.key.pem"; - cert = "./ca/intermediate/certs/client@freeswitch-upstream.cert.pem"; - chain = "./ca/intermediate/certs/ca-chain.cert.pem"; - }; - }; - }; -}; diff --git a/libs/libblade/test/testcli.vcxproj b/libs/libblade/test/testcli.vcxproj deleted file mode 100644 index ef62a6cc8f..0000000000 --- a/libs/libblade/test/testcli.vcxproj +++ /dev/null @@ -1,217 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {CF89E839-AB50-4BBB-AC34-0D6232E1EBB5} - Win32Proj - testcli - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - false - MultiThreadedDebugDLL - - - Console - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;rpcrt4.lib;winmm.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;rpcrt4.lib;winmm.lib;%(AdditionalDependencies) - - - - - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - {1a234565-926d-49b2-83e4-d56e0c38c9f2} - - - {a185b162-6cb6-4502-b03f-b56f7699a8d9} - - - {a89d6d18-6203-4149-9051-f8e798e7a3e7} - - - - - - \ No newline at end of file diff --git a/libs/libblade/test/testcon.c b/libs/libblade/test/testcon.c deleted file mode 100644 index 4dffa70330..0000000000 --- a/libs/libblade/test/testcon.c +++ /dev/null @@ -1,569 +0,0 @@ -#include "blade.h" -#include "tap.h" - -#define CONSOLE_INPUT_MAX 512 - -ks_bool_t g_shutdown = KS_FALSE; - -void loop(blade_handle_t *bh); -void process_console_input(blade_handle_t *bh, char *line); - -typedef void (*command_callback)(blade_handle_t *bh, char *args); - -struct command_def_s { - const char *cmd; - command_callback callback; -}; - -void command_quit(blade_handle_t *bh, char *args); -void command_presence(blade_handle_t *bh, char *args); -void command_identity(blade_handle_t *bh, char *args); - -static const struct command_def_s command_defs[] = { - { "quit", command_quit }, - { "presence", command_presence }, - { "identity", command_identity }, - - { NULL, NULL } -}; - -struct testproto_s { - blade_handle_t *handle; - ks_pool_t *pool; - ks_hash_t *participants; - ks_hash_t *channels; -}; -typedef struct testproto_s testproto_t; - -testproto_t *g_test = NULL; - -static void testproto_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //testproto_t *test = (testproto_t *)ptr; - - //ks_assert(test); - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - break; - } -} - -ks_status_t testproto_create(testproto_t **testP, blade_handle_t *bh) -{ - testproto_t *test = NULL; - ks_pool_t *pool = NULL; - - ks_assert(testP); - ks_assert(bh); - - ks_pool_open(&pool); - ks_assert(pool); - - test = ks_pool_alloc(pool, sizeof(testproto_t)); - test->handle = bh; - test->pool = pool; - - ks_hash_create(&test->participants, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - ks_hash_create(&test->channels, KS_HASH_MODE_CASE_INSENSITIVE, KS_HASH_FLAG_RWLOCK | KS_HASH_FLAG_DUP_CHECK | KS_HASH_FLAG_FREE_KEY, pool); - - ks_pool_set_cleanup(test, NULL, testproto_cleanup); - - *testP = test; - - return KS_STATUS_SUCCESS; -} - -ks_status_t testproto_destroy(testproto_t **testP) -{ - testproto_t *test = NULL; - ks_pool_t *pool = NULL; - - ks_assert(testP); - ks_assert(*testP); - - test = *testP; - pool = test->pool; - - ks_pool_close(&pool); - - *testP = NULL; - - return KS_STATUS_SUCCESS; -} - -ks_bool_t test_publish_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - //testproto_t *test = NULL; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - - ks_assert(brpcres); - ks_assert(data); - - //test = (testproto_t *)data; - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - ks_log(KS_LOG_DEBUG, "Session (%s) publish response processing\n", blade_session_id_get(bs)); - - blade_session_read_unlock(bs); - - return KS_FALSE; -} - -ks_bool_t test_join_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - testproto_t *test = NULL; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - const char *requester_nodeid = NULL; - const char *key = NULL; - cJSON *params = NULL; - cJSON *channels = NULL; - cJSON *result = NULL; - - ks_assert(brpcreq); - ks_assert(data); - - test = (testproto_t *)data; - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - // session for execute response - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - requester_nodeid = blade_rpcexecute_request_requester_nodeid_get(brpcreq); - ks_assert(requester_nodeid); - - // inner rpcexecute parameters - params = blade_rpcexecute_request_params_get(brpcreq); - ks_assert(params); - - ks_log(KS_LOG_DEBUG, "Session (%s) test.join request processing\n", blade_session_id_get(bs)); - - // add to participants - key = ks_pstrdup(test->pool, requester_nodeid); - ks_assert(key); - - // @todo to properly maintain protocol details tied to a specific node like this participants list requires a way to know if a specific node of interest goes offline to cleanup associated details - // refer back to work notes on ideas about this - ks_hash_write_lock(test->participants); - ks_hash_insert(test->participants, (void *)key, (void *)KS_TRUE); - ks_hash_write_unlock(test->participants); - - // authorize channels with the master for the requester - channels = cJSON_CreateArray(); - cJSON_AddItemToArray(channels, cJSON_CreateString("channel")); - for (ks_hash_iterator_t *it = ks_hash_first(test->channels, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - cJSON_AddItemToArray(channels, cJSON_CreateString((const char *)key)); - } - - blade_handle_rpcauthorize(bh, requester_nodeid, KS_FALSE, "test", channels, NULL, NULL); - - cJSON_Delete(channels); - - // send rpcexecute response to the requester - result = cJSON_CreateObject(); - - blade_rpcexecute_response_send(brpcreq, result); - - cJSON_Delete(result); - - blade_session_read_unlock(bs); - - // broadcast to authorized nodes that have subscribed, that the requester has joined - params = cJSON_CreateObject(); - - cJSON_AddStringToObject(params, "joiner-nodeid", requester_nodeid); - - blade_handle_rpcbroadcast(bh, "test", "channel", "join", params, NULL, NULL); - - cJSON_Delete(params); - - return KS_FALSE; -} - -ks_bool_t test_leave_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - testproto_t *test = NULL; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - const char *requester_nodeid = NULL; - //const char *key = NULL; - cJSON *params = NULL; - cJSON *channels = NULL; - cJSON *result = NULL; - - ks_assert(brpcreq); - ks_assert(data); - - test = (testproto_t *)data; - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - requester_nodeid = blade_rpcexecute_request_requester_nodeid_get(brpcreq); - ks_assert(requester_nodeid); - - params = blade_rpcexecute_request_params_get(brpcreq); - ks_assert(params); - - ks_log(KS_LOG_DEBUG, "Session (%s) test.leave (%s) request processing\n", blade_session_id_get(bs), requester_nodeid); - - ks_hash_write_lock(test->participants); - ks_hash_remove(test->participants, (void *)requester_nodeid); - ks_hash_write_unlock(test->participants); - - // deauthorize channels with the master for the requester - channels = cJSON_CreateArray(); - cJSON_AddItemToArray(channels, cJSON_CreateString("channel")); - for (ks_hash_iterator_t *it = ks_hash_first(test->channels, KS_UNLOCKED); it; it = ks_hash_next(&it)) { - void *key = NULL; - void *value = NULL; - - ks_hash_this(it, (const void **)&key, NULL, &value); - cJSON_AddItemToArray(channels, cJSON_CreateString((const char *)key)); - } - - blade_handle_rpcauthorize(bh, requester_nodeid, KS_TRUE, "test", channels, NULL, NULL); - - cJSON_Delete(channels); - - // send rpcexecute response to the requester - result = cJSON_CreateObject(); - - blade_rpcexecute_response_send(brpcreq, result); - - cJSON_Delete(result); - - blade_session_read_unlock(bs); - - // broadcast to authorized nodes that have subscribed, that the requester has left - params = cJSON_CreateObject(); - - cJSON_AddStringToObject(params, "leaver-nodeid", requester_nodeid); - - blade_handle_rpcbroadcast(bh, "test", "channel", "leave", params, NULL, NULL); - - cJSON_Delete(params); - - return KS_FALSE; -} - -ks_bool_t test_talk_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - //testproto_t *test = NULL; - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - const char *requester_nodeid = NULL; - const char *text = NULL; - cJSON *params = NULL; - cJSON *result = NULL; - - ks_assert(brpcreq); - ks_assert(data); - - //test = (testproto_t *)data; - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - requester_nodeid = blade_rpcexecute_request_requester_nodeid_get(brpcreq); - ks_assert(requester_nodeid); - - params = blade_rpcexecute_request_params_get(brpcreq); - ks_assert(params); - - text = cJSON_GetObjectCstr(params, "text"); - ks_assert(text); - - ks_log(KS_LOG_DEBUG, "Session (%s) test.talk (%s) request processing\n", blade_session_id_get(bs), requester_nodeid); - - // send rpcexecute response to the requester - result = cJSON_CreateObject(); - - blade_rpcexecute_response_send(brpcreq, result); - - cJSON_Delete(result); - - blade_session_read_unlock(bs); - - // broadcast to authorized nodes that have subscribed, that the requester has said something - params = cJSON_CreateObject(); - - cJSON_AddStringToObject(params, "text", text); - - cJSON_AddStringToObject(params, "talker-nodeid", requester_nodeid); - - blade_handle_rpcbroadcast(bh, "test", "channel", "talk", params, NULL, NULL); - - cJSON_Delete(params); - - return KS_FALSE; -} - -ks_bool_t test_presence_request_handler(blade_rpc_request_t *brpcreq, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - const char *protocol = NULL; - const char *channel = NULL; - const char *event = NULL; - cJSON *params = NULL; - const char *nodeid = NULL; - - ks_assert(brpcreq); - ks_assert(data); - - bh = blade_rpc_request_handle_get(brpcreq); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_request_sessionid_get(brpcreq)); - ks_assert(bs); - - protocol = blade_rpcbroadcast_request_protocol_get(brpcreq); - channel = blade_rpcbroadcast_request_channel_get(brpcreq); - event = blade_rpcbroadcast_request_event_get(brpcreq); - - params = blade_rpcbroadcast_request_params_get(brpcreq); - nodeid = cJSON_GetObjectCstr(params, "nodeid"); - - ks_log(KS_LOG_DEBUG, "Session (%s) presence (protocol %s, channel %s, event %s for %s) request processing\n", blade_session_id_get(bs), protocol, channel, event, nodeid); - - return KS_FALSE; -} - -ks_bool_t test_register_response_handler(blade_rpc_response_t *brpcres, void *data) -{ - blade_handle_t *bh = NULL; - blade_session_t *bs = NULL; - - ks_assert(brpcres); - - bh = blade_rpc_response_handle_get(brpcres); - ks_assert(bh); - - bs = blade_sessionmgr_session_lookup(blade_handle_sessionmgr_get(bh), blade_rpc_response_sessionid_get(brpcres)); - ks_assert(bs); - - ks_log(KS_LOG_DEBUG, "Session (%s) register response processing\n", blade_session_id_get(bs)); - - blade_session_read_unlock(bs); - - return KS_FALSE; -} - - -int main(int argc, char **argv) -{ - blade_handle_t *bh = NULL; - ks_pool_t *pool = NULL; - config_t config; - config_setting_t *config_blade = NULL; - const char *cfgpath = "testcon.cfg"; - const char *autoconnect = NULL; - - ks_global_set_default_logger(KS_LOG_LEVEL_DEBUG); - - blade_init(); - - blade_handle_create(&bh); - ks_assert(bh); - - pool = ks_pool_get(bh); - ks_assert(pool); - - if (argc > 1) autoconnect = argv[1]; - - config_init(&config); - if (!config_read_file(&config, cfgpath)) { - ks_log(KS_LOG_ERROR, "%s:%d - %s\n", config_error_file(&config), config_error_line(&config), config_error_text(&config)); - config_destroy(&config); - return EXIT_FAILURE; - } - config_blade = config_lookup(&config, "blade"); - if (!config_blade) { - ks_log(KS_LOG_ERROR, "Missing 'blade' config group\n"); - config_destroy(&config); - return EXIT_FAILURE; - } - if (config_setting_type(config_blade) != CONFIG_TYPE_GROUP) { - ks_log(KS_LOG_ERROR, "The 'blade' config setting is not a group\n"); - return EXIT_FAILURE; - } - - if (blade_handle_startup(bh, config_blade) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_ERROR, "Blade startup failed\n"); - return EXIT_FAILURE; - } - - testproto_create(&g_test, bh); - - if (autoconnect) { - blade_connection_t *bc = NULL; - blade_identity_t *target = NULL; - ks_bool_t connected = KS_FALSE; - blade_rpc_t *brpc = NULL; - - blade_identity_create(&target, ks_pool_get(bh)); - - if (blade_identity_parse(target, autoconnect) == KS_STATUS_SUCCESS) connected = blade_handle_connect(bh, &bc, target, NULL) == KS_STATUS_SUCCESS; - - blade_identity_destroy(&target); - - if (connected) { - cJSON *channels = NULL; - cJSON *entry = NULL; - - // @todo use session state change callback to know when the session is ready after blade.connect, this hack temporarily ensures it's ready before trying to publish upstream - ks_sleep_ms(3000); - - blade_rpc_create(&brpc, bh, "test.join", "test", test_join_request_handler, (void *)g_test); - blade_rpcmgr_protocolrpc_add(blade_handle_rpcmgr_get(bh), brpc); - - blade_rpc_create(&brpc, bh, "test.leave", "test", test_leave_request_handler, (void *)g_test); - blade_rpcmgr_protocolrpc_add(blade_handle_rpcmgr_get(bh), brpc); - - blade_rpc_create(&brpc, bh, "test.talk", "test", test_talk_request_handler, (void *)g_test); - blade_rpcmgr_protocolrpc_add(blade_handle_rpcmgr_get(bh), brpc); - - channels = cJSON_CreateArray(); - entry = cJSON_CreateObject(); - cJSON_AddStringToObject(entry, "name", "channel"); - cJSON_AddNumberToObject(entry, "flags", BLADE_CHANNEL_FLAGS_NONE); - cJSON_AddItemToArray(channels, entry); - - blade_handle_rpcpublish(bh, BLADE_RPCPUBLISH_COMMAND_CONTROLLER_ADD, "test", channels, test_publish_response_handler, (void *)g_test); - - cJSON_Delete(channels); - } - } - - loop(bh); - - blade_handle_destroy(&bh); - - testproto_destroy(&g_test); - - config_destroy(&config); - - blade_shutdown(); - - return 0; -} - -void loop(blade_handle_t *bh) -{ - char buf[CONSOLE_INPUT_MAX]; - while (!g_shutdown) { - if (!fgets(buf, CONSOLE_INPUT_MAX, stdin)) break; - - for (int index = 0; buf[index]; ++index) { - if (buf[index] == '\r' || buf[index] == '\n') { - buf[index] = '\0'; - break; - } - } - process_console_input(bh, buf); - } -} - -void parse_argument(char **input, char **arg, char terminator) -{ - char *tmp; - - ks_assert(input); - ks_assert(*input); - ks_assert(arg); - - tmp = *input; - *arg = tmp; - - while (*tmp && *tmp != terminator) ++tmp; - if (*tmp == terminator) { - *tmp = '\0'; - ++tmp; - } - *input = tmp; -} - -void process_console_input(blade_handle_t *bh, char *line) -{ - char *args = line; - char *cmd = NULL; - ks_bool_t found = KS_FALSE; - - parse_argument(&args, &cmd, ' '); - - ks_log(KS_LOG_DEBUG, "Command: %s, Args: %s\n", cmd, args); - - for (int32_t index = 0; command_defs[index].cmd; ++index) { - if (!strcmp(command_defs[index].cmd, cmd)) { - found = KS_TRUE; - command_defs[index].callback(bh, args); - } - } - if (!found) ks_log(KS_LOG_INFO, "Command '%s' unknown.\n", cmd); -} - -void command_quit(blade_handle_t *bh, char *args) -{ - ks_assert(bh); - ks_assert(args); - - g_shutdown = KS_TRUE; -} - -void command_presence(blade_handle_t *bh, char *args) -{ - cJSON *channels = NULL; - - ks_assert(bh); - ks_assert(args); - - channels = cJSON_CreateArray(); - cJSON_AddItemToArray(channels, cJSON_CreateString("join")); - cJSON_AddItemToArray(channels, cJSON_CreateString("leave")); - - blade_handle_rpcsubscribe(bh, BLADE_RPCSUBSCRIBE_COMMAND_SUBSCRIBER_ADD, "blade.presence", channels, NULL, NULL, test_presence_request_handler, (void *)g_test); -} - -void command_identity(blade_handle_t *bh, char *args) -{ - ks_assert(bh); - ks_assert(args); - - blade_handle_rpcregister(bh, "blade:testcon@freeswitch.com", test_register_response_handler, NULL); -} - -/* For Emacs: -* Local Variables: -* mode:c -* indent-tabs-mode:t -* tab-width:4 -* c-basic-offset:4 -* End: -* For VIM: -* vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: -*/ diff --git a/libs/libblade/test/testcon.cfg b/libs/libblade/test/testcon.cfg deleted file mode 100644 index 63f6102ba4..0000000000 --- a/libs/libblade/test/testcon.cfg +++ /dev/null @@ -1,27 +0,0 @@ -blade: -{ - transport: - { - wss: - { - ssl: - { - key = "./ca/intermediate/private/controller@freeswitch-upstream.key.pem"; - cert = "./ca/intermediate/certs/controller@freeswitch-upstream.cert.pem"; - chain = "./ca/intermediate/certs/ca-chain.cert.pem"; - }; - endpoints: - { - ipv4 = ( { address = "0.0.0.0", port = 2101 } ); - ipv6 = ( { address = "::", port = 2101 } ); - backlog = 128; - ssl: - { - key = "./ca/intermediate/private/controller@freeswitch-downstream.key.pem"; - cert = "./ca/intermediate/certs/controller@freeswitch-downstream.cert.pem"; - chain = "./ca/intermediate/certs/ca-chain.cert.pem"; - }; - }; - }; - }; -}; diff --git a/libs/libblade/test/testcon.vcxproj b/libs/libblade/test/testcon.vcxproj deleted file mode 100644 index 8c24d144be..0000000000 --- a/libs/libblade/test/testcon.vcxproj +++ /dev/null @@ -1,217 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {D67EEF66-B323-4BCF-9E3C-3A640B9949B7} - Win32Proj - testcon - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)..\libks\src\include;$(SolutionDir)..\libsodium-$(SodiumVersion)\src\libsodium\include;$(SolutionDir)..\libconfig-$(ConfigVersion)\lib;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - false - MultiThreadedDebugDLL - - - Console - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;rpcrt4.lib;winmm.lib;%(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - true - ../src/include;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;rpcrt4.lib;winmm.lib;%(AdditionalDependencies) - - - - - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - {1a234565-926d-49b2-83e4-d56e0c38c9f2} - - - {a185b162-6cb6-4502-b03f-b56f7699a8d9} - - - {a89d6d18-6203-4149-9051-f8e798e7a3e7} - - - - - - \ No newline at end of file diff --git a/libs/libblade/test/testdht2.c b/libs/libblade/test/testdht2.c deleted file mode 100644 index 0c726dcb73..0000000000 --- a/libs/libblade/test/testdht2.c +++ /dev/null @@ -1,385 +0,0 @@ -#include -#include -#include -#include - -ks_dht_storageitem_skey_t sk; -ks_dht_storageitem_pkey_t pk; - -ks_status_t dht2_updated_callback(ks_dht_t *dht, ks_dht_storageitem_t *item) -{ - diag("dht2_updated_callback\n"); - return KS_STATUS_SUCCESS; -} - -ks_status_t dht2_distribute_callback(ks_dht_t *dht, ks_dht_storageitem_t *item) -{ - diag("dht2_distribute_callback\n"); - return KS_STATUS_SUCCESS; -} - -ks_status_t dht2_put_callback(ks_dht_t *dht, ks_dht_job_t *job) -{ - diag("dht2_put_callback\n"); - return KS_STATUS_SUCCESS; -} - -ks_status_t dht2_get_token_callback(ks_dht_t *dht, ks_dht_job_t *job) -{ - char buf[KS_DHT_TOKEN_SIZE * 2 + 1]; - const char *v = "Hello World!"; - size_t v_len = strlen(v); - ks_dht_storageitem_signature_t sig; - ks_dht_storageitem_t *mutable = NULL; - - diag("dht2_get_token_callback %s\n", ks_dht_hex(job->response_token.token, buf, KS_DHT_TOKEN_SIZE)); - - ks_dht_storageitem_signature_generate(&sig, &sk, NULL, 0, 1, (uint8_t *)v, v_len); - // @todo check if exists - ks_dht_storageitem_create_mutable(&mutable, dht->pool, &job->query_target, (uint8_t *)v, v_len, &pk, NULL, 0, 1, &sig); - mutable->sk = sk; - ks_dht_storageitems_insert(dht, mutable); - - ks_dht_put(dht, &job->raddr, dht2_put_callback, NULL, &job->response_token, 0, mutable); - return KS_STATUS_SUCCESS; -} - -ks_status_t dht2_search_callback(ks_dht_t *dht, ks_dht_job_t *job) -{ - ks_dht_search_t *search = (ks_dht_search_t *)job->data; - diag("dht2_search_callback %d\n", search->results_length); - return KS_STATUS_SUCCESS; -} - -int main() { - //ks_size_t buflen; - ks_status_t err; - int mask = 0; - ks_dht_nodeid_t nodeid; - ks_dht_t *dht1 = NULL; - ks_dht_t *dht2 = NULL; - ks_dht_t *dht3 = NULL; - ks_dht_endpoint_t *ep1; - ks_dht_endpoint_t *ep2; - ks_dht_endpoint_t *ep3; - ks_bool_t have_v4, have_v6; - char v4[48] = {0}, v6[48] = {0}; - ks_sockaddr_t addr; - ks_sockaddr_t raddr1; - //ks_sockaddr_t raddr2; - //ks_sockaddr_t raddr3; - ks_dht_nodeid_t target; - //ks_dht_storageitem_t *immutable = NULL; - ks_dht_storageitem_t *mutable1 = NULL; - ks_dht_storageitem_t *mutable2 = NULL; - const char *v = "Hello World!"; - size_t v_len = strlen(v); - //ks_dht_storageitem_skey_t sk; //= { { 0xe0, 0x6d, 0x31, 0x83, 0xd1, 0x41, 0x59, 0x22, 0x84, 0x33, 0xed, 0x59, 0x92, 0x21, 0xb8, 0x0b, - //0xd0, 0xa5, 0xce, 0x83, 0x52, 0xe4, 0xbd, 0xf0, 0x26, 0x2f, 0x76, 0x78, 0x6e, 0xf1, 0xc7, 0x4d, - //0xb7, 0xe7, 0xa9, 0xfe, 0xa2, 0xc0, 0xeb, 0x26, 0x9d, 0x61, 0xe3, 0xb3, 0x8e, 0x45, 0x0a, 0x22, - //0xe7, 0x54, 0x94, 0x1a, 0xc7, 0x84, 0x79, 0xd6, 0xc5, 0x4e, 0x1f, 0xaf, 0x60, 0x37, 0x88, 0x1d } }; - //ks_dht_storageitem_pkey_t pk; //= { { 0x77, 0xff, 0x84, 0x90, 0x5a, 0x91, 0x93, 0x63, 0x67, 0xc0, 0x13, 0x60, 0x80, 0x31, 0x04, 0xf9, - //0x24, 0x32, 0xfc, 0xd9, 0x04, 0xa4, 0x35, 0x11, 0x87, 0x6d, 0xf5, 0xcd, 0xf3, 0xe7, 0xe5, 0x48 } }; - //uint8_t sk1[KS_DHT_STORAGEITEM_SKEY_SIZE]; - //uint8_t pk1[KS_DHT_STORAGEITEM_PKEY_SIZE]; - ks_dht_storageitem_signature_t sig; - //char sk_buf[KS_DHT_STORAGEITEM_SKEY_SIZE * 2 + 1]; - //char pk_buf[KS_DHT_STORAGEITEM_PKEY_SIZE * 2 + 1]; - //const char *test1vector = "3:seqi1e1:v12:Hello World!"; - //const char *test1vector = "4:salt6:foobar3:seqi1e1:v12:Hello World!"; - //size_t test1vector_len = strlen(test1vector); - //uint8_t test1vector_sig[KS_DHT_STORAGEITEM_SIGNATURE_SIZE]; - //char test1vector_buf[KS_DHT_STORAGEITEM_SIGNATURE_SIZE * 2 + 1]; - - err = ks_init(); - ok(!err); - - ks_global_set_default_logger(KS_LOG_LEVEL_INFO); - - err = ks_find_local_ip(v4, sizeof(v4), &mask, AF_INET, NULL); - ok(err == KS_STATUS_SUCCESS); - have_v4 = !zstr_buf(v4); - - //err = ks_find_local_ip(v6, sizeof(v6), NULL, AF_INET6, NULL); - //ok(err == KS_STATUS_SUCCESS); - have_v6 = KS_FALSE;//!zstr_buf(v6); - - ok(have_v4 || have_v6); - - if (have_v4) { - diag("Binding to %s on ipv4\n", v4); - } - if (have_v6) { - diag("Binding to %s on ipv6\n", v6); - } - - ks_dht_dehex(nodeid.id, "0000000000000000000000000000000000000001", KS_DHT_NODEID_SIZE); - err = ks_dht_create(&dht1, NULL, NULL, &nodeid); - ok(err == KS_STATUS_SUCCESS); - - ks_dht_dehex(nodeid.id, "0000000000000000000000000000000000000002", KS_DHT_NODEID_SIZE); - err = ks_dht_create(&dht2, NULL, NULL, &nodeid); - ok(err == KS_STATUS_SUCCESS); - - ks_dht_dehex(nodeid.id, "0000000000000000000000000000000000000003", KS_DHT_NODEID_SIZE); - err = ks_dht_create(&dht3, NULL, NULL, &nodeid); - ok(err == KS_STATUS_SUCCESS); - - if (have_v4) { - err = ks_addr_set(&addr, v4, KS_DHT_DEFAULT_PORT, AF_INET); - ok(err == KS_STATUS_SUCCESS); - - err = ks_dht_bind(dht1, &addr, &ep1); - ok(err == KS_STATUS_SUCCESS); - - raddr1 = addr; - - err = ks_addr_set(&addr, v4, KS_DHT_DEFAULT_PORT + 1, AF_INET); - ok(err == KS_STATUS_SUCCESS); - - err = ks_dht_bind(dht2, &addr, &ep2); - ok(err == KS_STATUS_SUCCESS); - - //raddr2 = addr; - - err = ks_addr_set(&addr, v4, KS_DHT_DEFAULT_PORT + 2, AF_INET); - ok(err == KS_STATUS_SUCCESS); - - err = ks_dht_bind(dht3, &addr, &ep3); - ok(err == KS_STATUS_SUCCESS); - - //raddr3 = addr; - } - - if (have_v6) { - err = ks_addr_set(&addr, v6, KS_DHT_DEFAULT_PORT, AF_INET6); - ok(err == KS_STATUS_SUCCESS); - - err = ks_dht_bind(dht1, &addr, NULL); - ok(err == KS_STATUS_SUCCESS); - - err = ks_addr_set(&addr, v6, KS_DHT_DEFAULT_PORT + 1, AF_INET6); - ok(err == KS_STATUS_SUCCESS); - - err = ks_dht_bind(dht2, &addr, NULL); - ok(err == KS_STATUS_SUCCESS); - - err = ks_addr_set(&addr, v6, KS_DHT_DEFAULT_PORT + 2, AF_INET6); - ok(err == KS_STATUS_SUCCESS); - - err = ks_dht_bind(dht3, &addr, NULL); - ok(err == KS_STATUS_SUCCESS); - } - - diag("Ping test\n"); - - ks_dht_ping(dht2, &raddr1, NULL, NULL); // (QUERYING) - - ks_dht_pulse(dht2, 100); // Send queued ping from dht2 to dht1 (RESPONDING) - - ks_dht_pulse(dht1, 100); // Receive and process ping query from dht2, queue and send ping response - - ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht2->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet - - ks_dht_pulse(dht2, 100); // Receive and process ping response from dht1 (PROCESSING then COMPLETING) - - ok(ks_dhtrt_find_node(dht2->rt_ipv4, dht1->nodeid) != NULL); // The node should be good, and thus be returned as good - - ks_dht_pulse(dht2, 100); // Call finish callback and purge the job (COMPLETING) - - diag("Pulsing for route table pings\n"); // Wait for route table pinging to catch up - for (int i = 0; i < 10; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht2->nodeid) != NULL); // The node should be good by now, and thus be returned as good - - - ks_dht_ping(dht3, &raddr1, NULL, NULL); // (QUERYING) - - ks_dht_pulse(dht3, 100); // Send queued ping from dht3 to dht1 (RESPONDING) - - ks_dht_pulse(dht1, 100); // Receive and process ping query from dht3, queue and send ping response - - ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht3->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet - - ks_dht_pulse(dht3, 100); // Receive and process ping response from dht1 (PROCESSING then COMPLETING) - - ok(ks_dhtrt_find_node(dht3->rt_ipv4, dht1->nodeid) != NULL); // The node should be good, and thus be returned as good - - ks_dht_pulse(dht3, 100); // Call finish callback and purge the job (COMPLETING) - - diag("Pulsing for route table pings\n"); // Wait for route table pinging to catch up - for (int i = 0; i < 10; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht2->nodeid) != NULL); // The node should be good by now, and thus be returned as good - - // Test bootstrap find_node from dht3 to dht1 to find dht2 nodeid - - /* - diag("Find_Node test\n"); - - ks_dht_findnode(dht3, NULL, &raddr1, NULL, NULL, &dht2->nodeid); - - ks_dht_pulse(dht3, 100); // Send queued findnode from dht3 to dht1 - - ks_dht_pulse(dht1, 100); // Receive and process findnode query from dht3, queue and send findnode response - - ok(ks_dhtrt_find_node(dht1->rt_ipv4, dht3->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet - - ks_dht_pulse(dht3, 100); // Receive and process findnode response from dht1 - - ks_dht_pulse(dht3, 100); // Call finish callback and purge the job (COMPLETING) - - ok(ks_dhtrt_find_node(dht3->rt_ipv4, dht2->nodeid) == NULL); // The node should be dubious, and thus not be returned as good yet - - diag("Pulsing for route table pings\n"); // Wait for route table pinging to catch up - for (int i = 0; i < 10; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - ok(ks_dhtrt_find_node(dht3->rt_ipv4, dht2->nodeid) != NULL); // The node should be good by now, and thus be returned as good - */ - - diag("Search test\n"); - - ks_dht_search(dht3, dht2_search_callback, NULL, dht3->rt_ipv4, &dht2->nodeid); - diag("Pulsing for route table pings\n"); // Wait for route table pinging to catch up - for (int i = 0; i < 20; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - - //diag("Get test\n"); - - - /* - ks_dht_storageitem_target_immutable((uint8_t *)v, v_len, &target); - ks_dht_storageitem_create_immutable(&immutable, dht1->pool, &target, (uint8_t *)v, v_len); - ks_dht_storageitems_insert(dht1, immutable); - */ - - /* - crypto_sign_keypair(pk.key, sk.key); - - ks_dht_storageitem_signature_generate(&sig, &sk, NULL, 0, 1, (uint8_t *)v, v_len); - ks_dht_storageitem_target_mutable(&pk, NULL, 0, &target); - ks_dht_storageitem_create_mutable(&mutable, dht1->pool, &target, (uint8_t *)v, v_len, &pk, NULL, 0, 1, &sig); - mutable->sk = sk; - ks_dht_storageitems_insert(dht1, mutable); - - ks_dht_get(dht2, &raddr1, dht2_get_callback, NULL, &target, NULL, 0); - - ks_dht_pulse(dht2, 100); // send get query - - ks_dht_pulse(dht1, 100); // receive get query and send get response - - ks_dht_pulse(dht2, 100); // receive get response - - ok(ks_dht_storageitems_find(dht2, &target) != NULL); // item should be verified and stored - - ks_dht_pulse(dht2, 100); // Call finish callback and purge the job (COMPLETING) - */ - - /* - diag("Put test\n"); - - crypto_sign_keypair(pk.key, sk.key); - - ks_dht_storageitem_target_mutable(&pk, NULL, 0, &target); - - ks_dht_get(dht2, &raddr1, dht2_get_token_callback, NULL, &target, NULL, 0); // create job - - for (int i = 0; i < 20; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - */ - - /* - diag("Publish test\n"); - - crypto_sign_keypair(pk.key, sk.key); - - ks_dht_storageitem_target_mutable(&pk, NULL, 0, &target); - - ks_dht_storageitem_signature_generate(&sig, &sk, NULL, 0, 1, (uint8_t *)v, v_len); - - ks_dht_storageitem_create_mutable(&mutable, dht2->pool, &target, (uint8_t *)v, v_len, &pk, NULL, 0, 1, &sig); - mutable->sk = sk; - ks_dht_storageitems_insert(dht2, mutable); - - ks_dht_publish(dht2, &raddr1, dht2_put_callback, NULL, 0, mutable); // create job - - for (int i = 0; i < 20; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - */ - - - diag("Distribute test\n"); - - crypto_sign_keypair(pk.key, sk.key); - - ks_dht_storageitem_target_mutable(&pk, NULL, 0, &target); - - ks_dht_storageitem_signature_generate(&sig, &sk, NULL, 0, 1, (uint8_t *)v, v_len); - - ks_dht_storageitem_create_mutable(&mutable2, dht2->pool, &target, (uint8_t *)v, v_len, &pk, NULL, 0, 1, &sig); - mutable2->sk = sk; - ks_dht_storageitems_insert(dht2, mutable2); - - ks_dht_distribute(dht2, dht2_distribute_callback, NULL, dht2->rt_ipv4, 0, mutable2); // create job - - for (int i = 0; i < 30; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - ks_dht_storageitem_dereference(mutable2); - ok(mutable2->refc == 0); - - mutable1 = ks_dht_storageitems_find(dht1, &target); - ok(mutable1 != NULL); - - ks_dht_storageitem_callback(mutable1, dht2_updated_callback); - ks_dht_storageitem_callback(mutable2, dht2_updated_callback); - - ks_dht_storageitem_signature_generate(&sig, &sk, NULL, 0, 2, (uint8_t *)v, v_len); - mutable1->seq = 2; - mutable1->sig = sig; - - //ks_dht_storageitem_signature_generate(&sig, &sk, NULL, 0, 2, (uint8_t *)v, v_len); - //mutable2->seq = 2; - //mutable2->sig = sig; - - ks_dht_distribute(dht2, dht2_distribute_callback, NULL, dht2->rt_ipv4, 0, mutable2); - for (int i = 0; i < 30; ++i) { - ks_dht_pulse(dht1, 100); - ks_dht_pulse(dht2, 100); - ks_dht_pulse(dht3, 100); - } - ks_dht_storageitem_dereference(mutable1); - - /* Cleanup and shutdown */ - diag("Cleanup\n"); - - ks_dht_destroy(&dht3); - - ks_dht_destroy(&dht2); - - ks_dht_destroy(&dht1); - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/.gitignore b/libs/libks/.gitignore deleted file mode 100644 index 740a5af167..0000000000 --- a/libs/libks/.gitignore +++ /dev/null @@ -1,10 +0,0 @@ -Makefile -Makefile.in -build/compile -build/libtool.m4 -build/ltoptions.m4 -build/ltsugar.m4 -build/ltversion.m4 -build/lt~obsolete.m4 -dht-example.id -configure diff --git a/libs/libks/AUTHORS b/libs/libks/AUTHORS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libks/CODING_GUIDELINES b/libs/libks/CODING_GUIDELINES deleted file mode 100644 index 223d3b87a9..0000000000 --- a/libs/libks/CODING_GUIDELINES +++ /dev/null @@ -1,108 +0,0 @@ -/* - * Copyright (c) 2007-2017, FreeSWITCH Solutions 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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. - */ - -/* -Functions that create and destroy objects always take pointer to pointer of that type. -Spaces after loop and conditional operators while, for, if etc. -Newlines after one or more declarations. -Newlines before and after loops. -Newlines before returns. -One-Line if/else sparingly only when very obvious exit from loop or return. -Use brackets even when not necessary other than the one-liners above. -Align the * in pointers to the type or function name (e.g char *foo, char *some_func(char *data) ) -Use typedefs for structs especially public-facing. -Only use // style-comments on tempory comments that will probably be removed eventually. -Add the emacs/vi comment to the bottom of every file. -Use Doxygen for function args. -Tabs not spaces. -Use flags as bitwise when possible, use arrays if going beyond 32 -Typedef all enums using UPPER_CASE notation for the values -*/ - -typedef enum { - SOME_FLAG_X = (1 << 0), - SOME_FLAG_Y = (1 << 1) -} some_flag_type_t; - -typedef enum { - SOME_TYPE_X = 1, - SOME_TYPE_Y, - SOME_TYPE_Z -} some_type_t; - - -KS_DECLARE(ks_status_t) function_example(somedata_t **data, ks_pool_t *pool) -{ - int var = 3, x = 0; - - if (!pool) return KS_STATUS_FAIL; - - for (x = 0; x < 100; x++) { - var += x; - } - - if (var > 20) { - var *= 2; - } else { - var *= 3; - } - - while (var) { - var--; - } - - if (var) { - *data = ks_pool_alloc(pool, sizeof(*data)); - (*data)->pool = pool; - - return KS_STATUS_SUCCESS; - - } else { - *data = NULL; - - return KS_STATUS_FAIL; - } - -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/COPYING b/libs/libks/COPYING deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libks/ChangeLog b/libs/libks/ChangeLog deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libks/INSTALL b/libs/libks/INSTALL deleted file mode 100644 index 2099840756..0000000000 --- a/libs/libks/INSTALL +++ /dev/null @@ -1,370 +0,0 @@ -Installation Instructions -************************* - -Copyright (C) 1994-1996, 1999-2002, 2004-2013 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 command `./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 `' 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 limitation. Until the limitation is lifted, you can use -this workaround: - - CONFIG_SHELL=/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/libs/libks/Makefile.am b/libs/libks/Makefile.am deleted file mode 100644 index 13a87b8588..0000000000 --- a/libs/libks/Makefile.am +++ /dev/null @@ -1,31 +0,0 @@ -ACLOCAL_AMFLAGS=-I build -EXTRA_DIST = -SUBDIRS = . test -AUTOMAKE_OPTIONS = subdir-objects - -AM_CFLAGS += -I$(top_srcdir)/src -I$(top_srcdir)/src/include -I$(top_srcdir)/crypt -O0 -AM_CPPFLAGS = $(AM_CFLAGS) - -lib_LTLIBRARIES = libks.la -libks_la_SOURCES = src/ks.c src/ks_string.c src/ks_json.c src/cJSON.c src/cJSON_Utils.c src/ks_thread.c src/ks_thread_pool.c src/ks_mutex.c src/ks_config.c -libks_la_SOURCES += src/ks_log.c src/ks_socket.c src/ks_buffer.c src/ks_pool.c src/simclist.c -libks_la_SOURCES += src/ks_time.c src/ks_printf.c src/ks_hash.c src/ks_q.c src/ks_dso.c -libks_la_SOURCES += src/ks_ssl.c src/kws.c src/ks_rng.c src/ks_base64.c -libks_la_SOURCES += crypt/aeskey.c crypt/aestab.c crypt/sha2.c crypt/aes_modes.c crypt/aescrypt.c -libks_la_SOURCES += src/ks_acl.c src/ks_sb.c - -libks_la_CFLAGS = $(AM_CFLAGS) -libks_la_CPPFLAGS = -DPOSIX -libks_la_LDFLAGS = $(AM_LDFLAGS) -version-info 0:1:0 -lncurses -lpthread -lm - -library_includedir = $(prefix)/include -library_include_HEADERS = src/include/ks_config.h src/include/ks.h src/include/ks_threadmutex.h src/include/ks_json.h src/include/ks_buffer.h -library_include_HEADERS += src/include/ks_thread_pool.h src/include/ks_cJSON.h src/include/ks_cJSON_Utils.h -library_include_HEADERS += src/include/ks_pool.h src/include/simclist.h src/include/ks_time.h src/include/ks_q.h src/include/ks_socket.h -library_include_HEADERS += src/include/ks_dso.h src/include/ks_platform.h src/include/ks_types.h src/include/ks_rng.h -library_include_HEADERS += src/include/ks_printf.h src/include/ks_hash.h src/include/ks_ssl.h src/include/kws.h -library_include_HEADERS += src/include/ks_base64.h -library_include_HEADERS += src/include/ks_acl.h src/include/ks_sb.h - -tests: libks.la - $(MAKE) -C test tests diff --git a/libs/libks/NEWS b/libs/libks/NEWS deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libks/README b/libs/libks/README deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/libs/libks/acinclude.m4 b/libs/libks/acinclude.m4 deleted file mode 100644 index 1b464ca796..0000000000 --- a/libs/libks/acinclude.m4 +++ /dev/null @@ -1,7 +0,0 @@ -m4_include([build/config/ax_compiler_vendor.m4]) -m4_include([build/config/ax_cflags_warn_all_ansi.m4]) -m4_include([build/config/ax_cc_maxopt.m4]) -m4_include([build/config/ax_check_compiler_flags.m4]) -m4_include([build/config/ac_gcc_archflag.m4]) -m4_include([build/config/ac_gcc_x86_cpuid.m4]) -m4_include([build/config/sac-openssl.m4]) diff --git a/libs/libks/bootstrap.sh b/libs/libks/bootstrap.sh deleted file mode 100755 index e8ca45f592..0000000000 --- a/libs/libks/bootstrap.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -set -x -${AUTORECONF:-autoreconf} -fi diff --git a/libs/libks/build/config/ac_cflags_gcc_option.m4 b/libs/libks/build/config/ac_cflags_gcc_option.m4 deleted file mode 100644 index e651a5e6c5..0000000000 --- a/libs/libks/build/config/ac_cflags_gcc_option.m4 +++ /dev/null @@ -1,142 +0,0 @@ -AC_DEFUN([AX_CFLAGS_GCC_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($2,$2,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for gcc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($2,$2,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl ------------------------------------------------------------------------- - -AC_DEFUN([AX_CFLAGS_GCC_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_gcc_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($1,$1,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_GCC_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_gcc_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for gcc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "-pedantic % m4_ifval($1,$1,-option)" dnl GCC - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -AC_DEFUN([AX_CFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, -[AX_CFLAGS_GCC_OPTION_NEW($@)],[AX_CFLAGS_GCC_OPTION_OLD($@)])]) - -AC_DEFUN([AX_CXXFLAGS_GCC_OPTION],[ifelse(m4_bregexp([$2],[-]),-1, -[AX_CXXFLAGS_GCC_OPTION_NEW($@)],[AX_CXXFLAGS_GCC_OPTION_OLD($@)])]) - diff --git a/libs/libks/build/config/ac_cflags_sun_option.m4 b/libs/libks/build/config/ac_cflags_sun_option.m4 deleted file mode 100644 index a09e6fb695..0000000000 --- a/libs/libks/build/config/ac_cflags_sun_option.m4 +++ /dev/null @@ -1,140 +0,0 @@ -AC_DEFUN([AX_CFLAGS_SUN_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_sun_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for sun/cc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($2,$2,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_SUN_OPTION_OLD], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_sun_option_$2])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for sun/cc m4_ifval($2,$2,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($2,$2,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl ----------------------------------------------------------------------- - -AC_DEFUN([AX_CFLAGS_SUN_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_sun_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for sun/cc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($1,$1,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_SUN_OPTION_NEW], [dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_sun_option_$1])dnl -AC_CACHE_CHECK([m4_ifval($2,$2,FLAGS) for sun/cc m4_ifval($1,$1,-option)], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -for ac_arg dnl -in "+xstrconst % -xc99=all m4_ifval($1,$1,-option)" dnl Solaris C - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($2,$2,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($2,$2,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR"]) - m4_ifval($2,$2,FLAGS)="$m4_ifval($2,$2,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -AC_DEFUN([AX_CFLAGS_SUN_OPTION],[ifelse(m4_regexp([$2],[-]),-1, -[AX_CFLAGS_SUN_OPTION_NEW($@)],[AX_CFLAGS_SUN_OPTION_OLD($@)])]) - -AC_DEFUN([AX_CXXFLAGS_SUN_OPTION],[ifelse(m4_regexp([$2],[-]),-1, -[AX_CXXFLAGS_SUN_OPTION_NEW($@)],[AX_CXXFLAGS_SUN_OPTION_OLD($@)])]) - diff --git a/libs/libks/build/config/ac_gcc_archflag.m4 b/libs/libks/build/config/ac_gcc_archflag.m4 deleted file mode 100644 index b38a564902..0000000000 --- a/libs/libks/build/config/ac_gcc_archflag.m4 +++ /dev/null @@ -1,148 +0,0 @@ -AC_DEFUN([AX_GCC_ARCHFLAG], -[AC_REQUIRE([AC_PROG_CC]) - -AC_ARG_WITH(gcc-arch, [AC_HELP_STRING([--with-gcc-arch=], [use architecture for gcc -march/-mtune, instead of guessing])], - ax_gcc_arch=$withval, ax_gcc_arch=yes) - -AC_MSG_CHECKING([for gcc architecture flag]) -AC_MSG_RESULT([]) -AC_CACHE_VAL(ax_cv_gcc_archflag, -[ -ax_cv_gcc_archflag="unknown" - -if test "$GCC" = yes; then - -if test "x$ax_gcc_arch" = xyes; then -ax_gcc_arch="" -if test "$cross_compiling" = no; then -case $host_cpu in - i[[3456]]86*|x86_64*) # use cpuid codes, in part from x86info-1.7 by D. Jones - AX_GCC_X86_CPUID(0) - AX_GCC_X86_CPUID(1) - case $ax_cv_gcc_x86_cpuid_0 in - *:756e6547:*:*) # Intel - case $ax_cv_gcc_x86_cpuid_1 in - *5[[48]]?:*:*:*) ax_gcc_arch="pentium-mmx pentium" ;; - *5??:*:*:*) ax_gcc_arch=pentium ;; - *6[[3456]]?:*:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; - *6a?:*[[01]]:*:*) ax_gcc_arch="pentium2 pentiumpro" ;; - *6a?:*[[234]]:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; - *6[[9d]]?:*:*:*) ax_gcc_arch="pentium-m pentium3 pentiumpro" ;; - *6[[78b]]?:*:*:*) ax_gcc_arch="pentium3 pentiumpro" ;; - *6??:*:*:*) ax_gcc_arch=pentiumpro ;; - *f3[[347]]:*:*:*|*f4[1347]:*:*:*) - case $host_cpu in - x86_64*) ax_gcc_arch="nocona pentium4 pentiumpro" ;; - *) ax_gcc_arch="prescott pentium4 pentiumpro" ;; - esac ;; - *f??:*:*:*) ax_gcc_arch="pentium4 pentiumpro";; - esac ;; - *:68747541:*:*) # AMD - case $ax_cv_gcc_x86_cpuid_1 in - *5[[67]]?:*:*:*) ax_gcc_arch=k6 ;; - *5[[8d]]?:*:*:*) ax_gcc_arch="k6-2 k6" ;; - *5[[9]]?:*:*:*) ax_gcc_arch="k6-3 k6" ;; - *60?:*:*:*) ax_gcc_arch=k7 ;; - *6[[12]]?:*:*:*) ax_gcc_arch="athlon k7" ;; - *6[[34]]?:*:*:*) ax_gcc_arch="athlon-tbird k7" ;; - *67?:*:*:*) ax_gcc_arch="athlon-4 athlon k7" ;; - *6[[68a]]?:*:*:*) - AX_GCC_X86_CPUID(0x80000006) # L2 cache size - case $ax_cv_gcc_x86_cpuid_0x80000006 in - *:*:*[[1-9a-f]]??????:*) # (L2 = ecx >> 16) >= 256 - ax_gcc_arch="athlon-xp athlon-4 athlon k7" ;; - *) ax_gcc_arch="athlon-4 athlon k7" ;; - esac ;; - *f[[4cef8b]]?:*:*:*) ax_gcc_arch="athlon64 k8" ;; - *f5?:*:*:*) ax_gcc_arch="opteron k8" ;; - *f7?:*:*:*) ax_gcc_arch="athlon-fx opteron k8" ;; - *f??:*:*:*) ax_gcc_arch="k8" ;; - esac ;; - *:746e6543:*:*) # IDT - case $ax_cv_gcc_x86_cpuid_1 in - *54?:*:*:*) ax_gcc_arch=winchip-c6 ;; - *58?:*:*:*) ax_gcc_arch=winchip2 ;; - *6[[78]]?:*:*:*) ax_gcc_arch=c3 ;; - *69?:*:*:*) ax_gcc_arch="c3-2 c3" ;; - esac ;; - esac - if test x"$ax_gcc_arch" = x; then # fallback - case $host_cpu in - i586*) ax_gcc_arch=pentium ;; - i686*) ax_gcc_arch=pentiumpro ;; - esac - fi - ;; - - sparc*) - AC_PATH_PROG([PRTDIAG], [prtdiag], [prtdiag], [$PATH:/usr/platform/`uname -i`/sbin/:/usr/platform/`uname -m`/sbin/]) - cputype=`(((grep cpu /proc/cpuinfo | cut -d: -f2) ; ($PRTDIAG -v |grep -i sparc) ; grep -i cpu /var/run/dmesg.boot ) | head -n 1) 2> /dev/null` - cputype=`echo "$cputype" | tr -d ' -' |tr $as_cr_LETTERS $as_cr_letters` - case $cputype in - *ultrasparciv*) ax_gcc_arch="ultrasparc4 ultrasparc3 ultrasparc v9" ;; - *ultrasparciii*) ax_gcc_arch="ultrasparc3 ultrasparc v9" ;; - *ultrasparc*) ax_gcc_arch="ultrasparc v9" ;; - *supersparc*|*tms390z5[[05]]*) ax_gcc_arch="supersparc v8" ;; - *hypersparc*|*rt62[[056]]*) ax_gcc_arch="hypersparc v8" ;; - *cypress*) ax_gcc_arch=cypress ;; - esac ;; - - alphaev5) ax_gcc_arch=ev5 ;; - alphaev56) ax_gcc_arch=ev56 ;; - alphapca56) ax_gcc_arch="pca56 ev56" ;; - alphapca57) ax_gcc_arch="pca57 pca56 ev56" ;; - alphaev6) ax_gcc_arch=ev6 ;; - alphaev67) ax_gcc_arch=ev67 ;; - alphaev68) ax_gcc_arch="ev68 ev67" ;; - alphaev69) ax_gcc_arch="ev69 ev68 ev67" ;; - alphaev7) ax_gcc_arch="ev7 ev69 ev68 ev67" ;; - alphaev79) ax_gcc_arch="ev79 ev7 ev69 ev68 ev67" ;; - - powerpc*) - cputype=`((grep cpu /proc/cpuinfo | head -n 1 | cut -d: -f2 | cut -d, -f1 | sed 's/ //g') ; /usr/bin/machine ; /bin/machine; grep CPU /var/run/dmesg.boot | head -n 1 | cut -d" " -f2) 2> /dev/null` - cputype=`echo $cputype | sed -e 's/ppc//g;s/ *//g'` - case $cputype in - *750*) ax_gcc_arch="750 G3" ;; - *740[[0-9]]*) ax_gcc_arch="$cputype 7400 G4" ;; - *74[[4-5]][[0-9]]*) ax_gcc_arch="$cputype 7450 G4" ;; - *74[[0-9]][[0-9]]*) ax_gcc_arch="$cputype G4" ;; - *970*) ax_gcc_arch="970 G5 power4";; - *POWER4*|*power4*|*gq*) ax_gcc_arch="power4 970";; - *POWER5*|*power5*|*gr*|*gs*) ax_gcc_arch="power5 power4 970";; - 603ev|8240) ax_gcc_arch="$cputype 603e 603";; - *) ax_gcc_arch=$cputype ;; - esac - ax_gcc_arch="$ax_gcc_arch powerpc" - ;; -esac -fi # not cross-compiling -fi # guess arch - -if test "x$ax_gcc_arch" != x -a "x$ax_gcc_arch" != xno; then -for arch in $ax_gcc_arch; do - if test "x[]m4_default([$1],yes)" = xyes; then # if we require portable code - flags="-mtune=$arch" - # -mcpu=$arch and m$arch generate nonportable code on every arch except - # x86. And some other arches (e.g. Alpha) don't accept -mtune. Grrr. - case $host_cpu in i*86|x86_64*) flags="$flags -mcpu=$arch -m$arch";; esac - else - flags="-march=$arch -mcpu=$arch -m$arch" - fi - for flag in $flags; do - AX_CHECK_COMPILER_FLAGS($flag, [ax_cv_gcc_archflag=$flag; break]) - done - test "x$ax_cv_gcc_archflag" = xunknown || break -done -fi - -fi # $GCC=yes -]) -AC_MSG_CHECKING([for gcc architecture flag]) -AC_MSG_RESULT($ax_cv_gcc_archflag) -if test "x$ax_cv_gcc_archflag" = xunknown; then - m4_default([$3],:) -else - m4_default([$2], [CFLAGS="$CFLAGS $ax_cv_gcc_archflag"]) -fi -]) - diff --git a/libs/libks/build/config/ac_gcc_x86_cpuid.m4 b/libs/libks/build/config/ac_gcc_x86_cpuid.m4 deleted file mode 100644 index 3cf22d0dde..0000000000 --- a/libs/libks/build/config/ac_gcc_x86_cpuid.m4 +++ /dev/null @@ -1,21 +0,0 @@ -AC_DEFUN([AX_GCC_X86_CPUID], -[AC_REQUIRE([AC_PROG_CC]) -AC_LANG_PUSH([C]) -AC_CACHE_CHECK(for x86 cpuid $1 output, ax_cv_gcc_x86_cpuid_$1, - [AC_RUN_IFELSE([AC_LANG_PROGRAM([#include ], [ - int op = $1, eax, ebx, ecx, edx; - FILE *f; - __asm__("cpuid" - : "=a" (eax), "=b" (ebx), "=c" (ecx), "=d" (edx) - : "a" (op)); - f = fopen("conftest_cpuid", "w"); if (!f) return 1; - fprintf(f, "%x:%x:%x:%x\n", eax, ebx, ecx, edx); - fclose(f); - return 0; -])], - [ax_cv_gcc_x86_cpuid_$1=`cat conftest_cpuid`; rm -f conftest_cpuid], - [ax_cv_gcc_x86_cpuid_$1=unknown; rm -f conftest_cpuid], - [ax_cv_gcc_x86_cpuid_$1=unknown])]) -AC_LANG_POP([C]) -]) - diff --git a/libs/libks/build/config/ac_prog_gzip.m4 b/libs/libks/build/config/ac_prog_gzip.m4 deleted file mode 100644 index f37a4cc9ce..0000000000 --- a/libs/libks/build/config/ac_prog_gzip.m4 +++ /dev/null @@ -1,9 +0,0 @@ -AC_DEFUN([AC_PROG_GZIP],[ -AC_CHECK_PROGS(gzip,[gzip],no) -export gzip; -if test $gzip = "no" ; -then - AC_MSG_ERROR([Unable to find the gzip application]); -fi -AC_SUBST(gzip) -]) diff --git a/libs/libks/build/config/ac_prog_wget.m4 b/libs/libks/build/config/ac_prog_wget.m4 deleted file mode 100644 index 56b6b8334f..0000000000 --- a/libs/libks/build/config/ac_prog_wget.m4 +++ /dev/null @@ -1,9 +0,0 @@ -AC_DEFUN([AC_PROG_WGET],[ -AC_CHECK_PROGS(wget,[wget],no) -export wget; -if test $wget = "no" ; -then - AC_MSG_ERROR([Unable to find the wget application]); -fi -AC_SUBST(wget) -]) diff --git a/libs/libks/build/config/ax_cc_maxopt.m4 b/libs/libks/build/config/ax_cc_maxopt.m4 deleted file mode 100644 index 6205ee84c8..0000000000 --- a/libs/libks/build/config/ax_cc_maxopt.m4 +++ /dev/null @@ -1,120 +0,0 @@ -AC_DEFUN([AX_CC_MAXOPT], -[ -AC_REQUIRE([AC_PROG_CC]) -AC_REQUIRE([AX_COMPILER_VENDOR]) - -AC_ARG_ENABLE(portable-binary, [AC_HELP_STRING([--enable-portable-binary], [disable compiler optimizations that would produce unportable binaries])], - acx_maxopt_portable=$withval, acx_maxopt_portable=no) - -# Try to determine "good" native compiler flags if none specified via CFLAGS -if test "$ac_test_CFLAGS" != "set"; then - CFLAGS="" - case $ax_cv_c_compiler_vendor in - dec) CFLAGS="-newc -w0 -O5 -ansi_alias -ansi_args -fp_reorder -tune host" - if test "x$acx_maxopt_portable" = xno; then - CFLAGS="$CFLAGS -arch host" - fi;; - - sun) CFLAGS="-native -fast -xO5 -dalign -xc99=all" - if test "x$acx_maxopt_portable" = xyes; then - CFLAGS="$CFLAGS -xarch=generic" - fi;; - - hp) CFLAGS="+Oall +Optrs_ansi +DSnative" - if test "x$acx_maxopt_portable" = xyes; then - CFLAGS="$CFLAGS +DAportable" - fi;; - - ibm) if test "x$acx_maxopt_portable" = xno; then - xlc_opt="-qarch=auto -qtune=auto" - else - xlc_opt="-qtune=auto" - fi - AX_CHECK_COMPILER_FLAGS($xlc_opt, - CFLAGS="-O3 -qansialias -w $xlc_opt", - [CFLAGS="-O3 -qansialias -w" - echo "******************************************************" - echo "* You seem to have the IBM C compiler. It is *" - echo "* recommended for best performance that you use: *" - echo "* *" - echo "* CFLAGS=-O3 -qarch=xxx -qtune=xxx -qansialias -w *" - echo "* ^^^ ^^^ *" - echo "* where xxx is pwr2, pwr3, 604, or whatever kind of *" - echo "* CPU you have. (Set the CFLAGS environment var. *" - echo "* and re-run configure.) For more info, man cc. *" - echo "******************************************************"]) - ;; - - intel) CFLAGS="-O3 -ansi_alias" - if test "x$acx_maxopt_portable" = xno; then - icc_archflag=unknown - icc_flags="" - case $host_cpu in - i686*|x86_64*) - # icc accepts gcc assembly syntax, so these should work: - AX_GCC_X86_CPUID(0) - AX_GCC_X86_CPUID(1) - case $ax_cv_gcc_x86_cpuid_0 in # see AX_GCC_ARCHFLAG - *:756e6547:*:*) # Intel - case $ax_cv_gcc_x86_cpuid_1 in - *6a?:*[[234]]:*:*|*6[[789b]]?:*:*:*) icc_flags="-xK";; - *f3[[347]]:*:*:*|*f4[1347]:*:*:*) icc_flags="-xP -xN -xW -xK";; - *f??:*:*:*) icc_flags="-xN -xW -xK";; - esac ;; - esac ;; - esac - if test "x$icc_flags" != x; then - for flag in $icc_flags; do - AX_CHECK_COMPILER_FLAGS($flag, [icc_archflag=$flag; break]) - done - fi - AC_MSG_CHECKING([for icc architecture flag]) - AC_MSG_RESULT($icc_archflag) - if test "x$icc_archflag" != xunknown; then - CFLAGS="$CFLAGS $icc_archflag" - fi - fi - ;; - - gnu) - # default optimization flags for gcc on all systems - CFLAGS="-O3 -fomit-frame-pointer" - - # -malign-double for x86 systems - AX_CHECK_COMPILER_FLAGS(-malign-double, CFLAGS="$CFLAGS -malign-double") - - # -fstrict-aliasing for gcc-2.95+ - AX_CHECK_COMPILER_FLAGS(-fstrict-aliasing, - CFLAGS="$CFLAGS -fstrict-aliasing") - - # note that we enable "unsafe" fp optimization with other compilers, too - AX_CHECK_COMPILER_FLAGS(-ffast-math, CFLAGS="$CFLAGS -ffast-math") - - AX_GCC_ARCHFLAG($acx_maxopt_portable) - ;; - esac - - if test -z "$CFLAGS"; then - echo "" - echo "********************************************************" - echo "* WARNING: Don't know the best CFLAGS for this system *" - echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "* (otherwise, a default of CFLAGS=-O3 will be used) *" - echo "********************************************************" - echo "" - CFLAGS="-O3" - fi - - AX_CHECK_COMPILER_FLAGS($CFLAGS, [], [ - echo "" - echo "********************************************************" - echo "* WARNING: The guessed CFLAGS don't seem to work with *" - echo "* your compiler. *" - echo "* Use ./configure CFLAGS=... to specify your own flags *" - echo "********************************************************" - echo "" - CFLAGS="" - ]) - -fi -]) diff --git a/libs/libks/build/config/ax_cflags_warn_all_ansi.m4 b/libs/libks/build/config/ax_cflags_warn_all_ansi.m4 deleted file mode 100644 index 5b35464457..0000000000 --- a/libs/libks/build/config/ax_cflags_warn_all_ansi.m4 +++ /dev/null @@ -1,94 +0,0 @@ -AC_DEFUN([AX_CFLAGS_WARN_ALL_ANSI],[dnl -AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all_ansi])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_C - ac_save_[]FLAGS="$[]FLAGS" -# IRIX C compiler: -# -use_readonly_const is the default for IRIX C, -# puts them into .rodata, but they are copied later. -# need to be "-G0 -rdatashared" for strictmode but -# I am not sure what effect that has really. - guidod -for ac_arg dnl -in "-pedantic % -Wall -std=c99 -pedantic" dnl GCC - "-xstrconst % -v -xc99=all" dnl Solaris C - "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix - " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX - " % -ansi -ansiE -fullwarn" dnl IRIX - "+ESlit % +w1 -Aa" dnl HP-UX C - "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) - "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ - AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - -dnl the only difference - the LANG selection... and the default FLAGS - -AC_DEFUN([AX_CXXFLAGS_WARN_ALL_ANSI],[dnl -AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl -AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all_ansi])dnl -AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum ansi warnings], -VAR,[VAR="no, unknown" - AC_LANG_SAVE - AC_LANG_CXX - ac_save_[]FLAGS="$[]FLAGS" -# IRIX C compiler: -# -use_readonly_const is the default for IRIX C, -# puts them into .rodata, but they are copied later. -# need to be "-G0 -rdatashared" for strictmode but -# I am not sure what effect that has really. - guidod -for ac_arg dnl -in "-pedantic % -Wall -ansi -pedantic" dnl GCC - "-xstrconst % -v -Xc" dnl Solaris C - "-std1 % -verbose -w0 -warnprotos -std1" dnl Digital Unix - " % -qlanglvl=ansi -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX - " % -ansi -ansiE -fullwarn" dnl IRIX - "+ESlit % +w1 -Aa" dnl HP-UX C - "-Xc % -pvctl[,]fullmsg -Xc" dnl NEC SX-5 (Super-UX 10) - "-h conform % -h msglevel 2 -h conform" dnl Cray C (Unicos) - # -do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'` - AC_TRY_COMPILE([],[return 0;], - [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break]) -done - FLAGS="$ac_save_[]FLAGS" - AC_LANG_RESTORE -]) -case ".$VAR" in - .ok|.ok,*) m4_ifvaln($3,$3) ;; - .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[ - AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;; - *) m4_ifvaln($3,$3,[ - if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null - then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR]) - else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"]) - m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR" - fi ]) ;; -esac -AS_VAR_POPDEF([VAR])dnl -AS_VAR_POPDEF([FLAGS])dnl -]) - diff --git a/libs/libks/build/config/ax_check_compiler_flags.m4 b/libs/libks/build/config/ax_check_compiler_flags.m4 deleted file mode 100644 index 73377b7c59..0000000000 --- a/libs/libks/build/config/ax_check_compiler_flags.m4 +++ /dev/null @@ -1,26 +0,0 @@ -AC_DEFUN([AX_CHECK_COMPILER_FLAGS], -[AC_PREREQ(2.59) dnl for _AC_LANG_PREFIX -AC_MSG_CHECKING([whether _AC_LANG compiler accepts $1]) -dnl Some hackery here since AC_CACHE_VAL can't handle a non-literal varname: -AS_LITERAL_IF([$1], - [AC_CACHE_VAL(AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1), [ - ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS - _AC_LANG_PREFIX[]FLAGS="$1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], - AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes, - AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no) - _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS])], - [ax_save_FLAGS=$[]_AC_LANG_PREFIX[]FLAGS - _AC_LANG_PREFIX[]FLAGS="$1" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM()], - eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=yes, - eval AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1)=no) - _AC_LANG_PREFIX[]FLAGS=$ax_save_FLAGS]) -eval ax_check_compiler_flags=$AS_TR_SH(ax_cv_[]_AC_LANG_ABBREV[]_flags_$1) -AC_MSG_RESULT($ax_check_compiler_flags) -if test "x$ax_check_compiler_flags" = xyes; then - m4_default([$2], :) -else - m4_default([$3], :) -fi -])dnl AX_CHECK_COMPILER_FLAG diff --git a/libs/libks/build/config/ax_compiler_vendor.m4 b/libs/libks/build/config/ax_compiler_vendor.m4 deleted file mode 100644 index a24a58da0f..0000000000 --- a/libs/libks/build/config/ax_compiler_vendor.m4 +++ /dev/null @@ -1,15 +0,0 @@ -AC_DEFUN([AX_COMPILER_VENDOR], -[ -AC_CACHE_CHECK([for _AC_LANG compiler vendor], ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor, - [ax_cv_[]_AC_LANG_ABBREV[]_compiler_vendor=unknown - # note: don't check for gcc first since some other compilers define __GNUC__ - for ventest in intel:__ICC,__ECC,__INTEL_COMPILER ibm:__xlc__,__xlC__,__IBMC__,__IBMCPP__ gnu:__GNUC__ sun:__SUNPRO_C,__SUNPRO_CC hp:__HP_cc,__HP_aCC dec:__DECC,__DECCXX,__DECC_VER,__DECCXX_VER borland:__BORLANDC__,__TURBOC__ comeau:__COMO__ cray:_CRAYC kai:__KCC lcc:__LCC__ metrowerks:__MWERKS__ sgi:__sgi,sgi microsoft:_MSC_VER watcom:__WATCOMC__ portland:__PGI; do - vencpp="defined("`echo $ventest | cut -d: -f2 | sed 's/,/) || defined(/g'`")" - AC_COMPILE_IFELSE([AC_LANG_PROGRAM(,[ -#if !($vencpp) - thisisanerror; -#endif -])], [ax_cv_]_AC_LANG_ABBREV[_compiler_vendor=`echo $ventest | cut -d: -f1`; break]) - done - ]) -]) diff --git a/libs/libks/build/config/sac-openssl.m4 b/libs/libks/build/config/sac-openssl.m4 deleted file mode 100644 index 289d3e132e..0000000000 --- a/libs/libks/build/config/sac-openssl.m4 +++ /dev/null @@ -1,49 +0,0 @@ -dnl ====================================================================== -dnl SAC_OPENSSL -dnl ====================================================================== -AC_DEFUN([SAC_OPENSSL], [ - -AC_ARG_WITH(openssl, -[ --with-openssl use OpenSSL [[enabled]]],, with_openssl=pkg-config) - -dnl SOSXXX:SAC_ASSERT_DEF([openssl libraries]) - - -if test "$with_openssl" = no ;then - : # No openssl -else - - if test "$with_openssl" = "pkg-config" ; then - PKG_CHECK_MODULES(openssl, openssl, - [HAVE_TLS=1 HAVE_OPENSSL=1 LIBS="$openssl_LIBS $LIBS"], - [HAVE_OPENSSL=0]) - fi - - if test x$HAVE_OPENSSL = x1 ; then - AC_DEFINE([HAVE_LIBCRYPTO], 1, [Define to 1 if you have the `crypto' library (-lcrypto).]) - AC_DEFINE([HAVE_LIBSSL], 1, [Define to 1 if you have the `ssl' library (-lssl).]) - else - AC_CHECK_HEADERS([openssl/tls1.h], [ - HAVE_OPENSSL=1 HAVE_TLS=1 - - AC_CHECK_LIB(crypto, BIO_new,, - HAVE_OPENSSL=0 - AC_MSG_WARN(OpenSSL crypto library was not found)) - - AC_CHECK_LIB(ssl, TLSv1_method,, - HAVE_TLS=0 - AC_MSG_WARN(OpenSSL protocol library was not found)) - ],[AC_MSG_WARN(OpenSSL include files were not found)],[#include ]) - fi - - if test x$HAVE_OPENSSL = x1; then - AC_DEFINE([HAVE_OPENSSL], 1, [Define to 1 if you have OpenSSL]) - fi - - if test x$HAVE_TLS = x1; then - AC_DEFINE([HAVE_TLS], 1, [Define to 1 if you have TLS]) - fi -fi - -AM_CONDITIONAL(HAVE_TLS, test x$HAVE_TLS = x1) -]) diff --git a/libs/libks/configure.ac b/libs/libks/configure.ac deleted file mode 100644 index 7151282fd5..0000000000 --- a/libs/libks/configure.ac +++ /dev/null @@ -1,256 +0,0 @@ -# -*- Autoconf -*- -# Process this file with autoconf to produce a configure script. - -AC_PREREQ(2.59) -AC_INIT(libks, 0.1, bugs@freeswitch.org) -AC_CONFIG_AUX_DIR(build) -AC_CONFIG_MACRO_DIR([build]) -AM_INIT_AUTOMAKE -AC_CONFIG_SRCDIR([src]) - -# disable checks -m4_defun([_LT_AC_LANG_CXX_CONFIG], [:]) -m4_defun([_LT_AC_LANG_F77_CONFIG], [:]) - -m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])]) - -# Checks for programs. -AC_PROG_CC -AC_PROG_CXX -AC_PROG_MAKE_SET -AC_PROG_LIBTOOL -AC_PROG_INSTALL - -# Optimize -AC_ARG_ENABLE(optimization, -[AC_HELP_STRING([--enable-optimization],[Set if you want us to add max optimising compiler flags])],[enable_optimizer="$enableval"],[enable_optimizer="no"]) - -if test "${enable_optimizer}" = "yes" ; then - AC_DEFINE([OPTIMZER],[],[Enable Optimization.]) - AX_CC_MAXOPT -fi - -# Enable debugging -AC_ARG_ENABLE(debug, -[AC_HELP_STRING([--enable-debug],[build with debug information])],[enable_debug="$enable_debug"],[enable_debug="no"]) - -if test "${enable_debug}" = "yes"; then - AC_DEFINE([DEBUG],[],[Enable extra debugging.]) -fi - -AM_CONDITIONAL([WANT_DEBUG],[test "${enable_debug}" = "yes"]) - -dnl check for the compiler used -AX_COMPILER_VENDOR - -case "$host" in - *-solaris2*) - if test "x${ax_cv_c_compiler_vendor}" = "xsun" ; then - AM_CFLAGS="-KPIC -DPIC" - AM_LDFLAGS="-R${prefix}/lib" - fi - ;; - *-darwin*) - if test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then - AM_CFLAGS="-DMACOSX" - fi - ;; - x86_64-unknown-linux-gnu) - AM_CFLAGS="-fPIC" - AM_LDFLAGS="" - ;; - i*6-unknown-linux-gnu) - AM_CFLAGS="-fpic" - AM_LDFLAGS="" - ;; - x86_64-*-freebsd*|amd64-*-freebsd*) - AM_CFLAGS="-fpic" - AM_LDFLAGS="" - ;; - i*6-*-freebsd*) - AM_CFLAGS="-fpic" - AM_LDFLAGS="" - ;; -esac - -AX_CFLAGS_WARN_ALL_ANSI - -AC_CHECK_LIB(rt, clock_gettime, [AC_DEFINE(HAVE_CLOCK_GETTIME, 1, [Define if you have clock_gettime()])]) -AC_CHECK_LIB(rt, clock_getres, [AC_DEFINE(HAVE_CLOCK_GETRES, 1, [Define if you have clock_getres()])]) -AC_CHECK_LIB(rt, clock_nanosleep, [AC_DEFINE(HAVE_CLOCK_NANOSLEEP, 1, [Define if you have clock_nanosleep()])]) -AC_CHECK_FUNCS([usleep]) - -# -# sched_setcheduler + round-robin scheduler prerequisites -# -AC_CHECK_HEADERS([sched.h byteswap.h sys/endian.h]) -AC_CHECK_DECL([SCHED_RR], - [AC_DEFINE([HAVE_SCHED_RR],[1],[SCHED_RR constant for sched_setscheduler])],, - [#ifdef HAVE_SCHED_H - #include - #endif]) -AC_CHECK_FUNCS([sched_setscheduler memmem]) - -if test "x${ac_cv_func_sched_setscheduler}" = "xyes" -a \ - "x${ac_cv_have_decl_SCHED_RR}" = "xyes" -then - AC_DEFINE([USE_SCHED_SETSCHEDULER],[1],[Enable round-robin scheduler using sched_setscheduler]) - AM_CFLAGS="${AM_CFLAGS} -DUSE_SCHED_SETSCHEDULER=1" -fi - - - -# -# gcc visibility cflag checks -# -AC_ARG_ENABLE([visibility], - [AS_HELP_STRING([--disable-visibility], [Disable or enable API visibility support (default: use if available)])], - [enable_visibility="${enableval}"], - [enable_visibility="detect"] -) -HAVE_VISIBILITY="no" - -if test "x${enable_visibility}" != "xno" ; then - - case "${ax_cv_c_compiler_vendor}" in - gnu) - save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} -fvisibility=hidden" - AC_MSG_CHECKING([whether the compiler supports -fvisibility=hidden]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [int foo __attribute__ ((visibility("default")));], - [;] - )], - - [AC_MSG_RESULT([yes]) - AM_CFLAGS="${AM_CFLAGS} -DKS_API_VISIBILITY=1 -DCJSON_API_VISIBILITY=1 -fvisibility=hidden" - AC_DEFINE([HAVE_VISIBILITY], [1], [GCC visibility support available]) - HAVE_VISIBILITY="yes"], - - [AC_MSG_RESULT([no])] - ) - CFLAGS="${save_CFLAGS}" - ;; - - sun) - save_CFLAGS="${CFLAGS}" - CFLAGS="${CFLAGS} -xldscope=hidden" - AC_MSG_CHECKING([whether the compiler supports -xldscope=hidden]) - AC_COMPILE_IFELSE( - [AC_LANG_PROGRAM( - [int foo __attribute__ ((visibility("default")));], - [;] - )], - - [AC_MSG_RESULT([yes]) - AM_CFLAGS="${AM_CFLAGS} -DKS_API_VISIBILITY=1 -DCJSON_API_VISIBILITY=1 -xldscope=hidden" - AC_DEFINE([HAVE_VISIBILITY], [1], [SUNCC visibility support available]) - HAVE_VISIBILITY="yes"], - - [AC_MSG_RESULT([no])] - ) - CFLAGS="${save_CFLAGS}" - ;; - - *) - if test "x${enable_visibility}" = "xyes" ; then - AC_MSG_ERROR([Non-GNU / SUN compilers are currently unsupported]) - else - AC_MSG_WARN([Non-GNU / SUN compilers are currently unsupported]) - fi - ;; - esac - - # - # visibility explicitly requested but not supported by this compiler => error - # - if test "x${enable_visibility}" = "xyes" -a "x${HAVE_VISIBILITY}" = "xno" ; then - AC_MSG_ERROR([API visibility not supported by this compiler]) - fi -fi - -AM_CFLAGS="${AM_CFLAGS} -Werror" -AC_SUBST(AM_CFLAGS) -AC_SUBST(AM_LDFLAGS) - -# Checks for header files. -AC_HEADER_DIRENT -AC_HEADER_STDC - -# Checks for typedefs, structures, and compiler characteristics. -AC_C_CONST -AC_C_INLINE -AC_TYPE_SIZE_T -AC_HEADER_TIME -AC_STRUCT_TM - -# Checks for library functions. -AC_PROG_GCC_TRADITIONAL -AC_FUNC_MALLOC -AC_TYPE_SIGNAL -AC_FUNC_STRFTIME - -AC_CHECK_LIB(pthread, pthread_setschedparam, [ -AC_DEFINE(HAVE_PTHREAD_SETSCHEDPARAM, 1, [Define if you have pthread_setschedparam()]) -AM_CFLAGS="${AM_CFLAGS} -DHAVE_PTHREAD_SETSCHEDPARAM=1" -]) - -AC_C_BIGENDIAN(AC_DEFINE([__BYTE_ORDER],__BIG_ENDIAN,[Big Endian]),AC_DEFINE([__BYTE_ORDER],__LITTLE_ENDIAN,[Little Endian])) -AC_DEFINE([__LITTLE_ENDIAN],1234,[for the places where it is not defined]) -AC_DEFINE([__BIG_ENDIAN],4321,[for the places where it is not defined]) - -path_remove () { - echo "$1" | tr ':' '\n' | grep -Fxv "$2" | tr '\n' ':' | sed 's/:$//' -} -path_push_unique () { - x="$(eval echo \$$1)" - x="$(path_remove "$x" "$2")" - if test -z "$x"; then - eval export $1="$2" - else - eval export $1="$2:$x" - fi -} - -case $host in - *-darwin*) - path_push_unique PKG_CONFIG_PATH /usr/local/opt/openssl/lib/pkgconfig - ;; -esac - -SAC_OPENSSL - -if test x$HAVE_OPENSSL = x1; then - openssl_CFLAGS="$openssl_CFLAGS -DHAVE_OPENSSL"; - AM_CFLAGS="${AM_CFLAGS} ${openssl_CFLAGS} -DHAVE_OPENSSL" - AM_LDFLAGS="${AM_LDFLAGS} ${openssl_LIBS}" -else - AC_MSG_ERROR([OpenSSL and associated developement headers required]) -fi - - -# Enable clang address sanitizer bit build -AC_ARG_ENABLE(address_sanitizer, - [AC_HELP_STRING([--enable-address-sanitizer],[build with address sanitizer])], - [enable_address_sanitizer="$enable_address_sanitizer"], - [enable_address_sanitizer="no"]) - -if test "${enable_address_sanitizer}" = "yes"; then - AM_CFLAGS="${AM_CFLAGS} -fsanitize=address -fno-omit-frame-pointer -O0" - AM_CXXFLAGS="${AM_CXXFLAGS} -fsanitize=address -fno-omit-frame-pointer -O0" - AM_LDFLAGS="${AM_LDFLAGS} -fsanitize=address -O0" - CFLAGS="${CFLAGS} -O0" -fi - -PKG_CHECK_MODULES([UUID], [uuid >= 1.0.0],[AC_MSG_RESULT([yes])],[AC_MSG_ERROR([libuuid is required])]) - -AM_CFLAGS="${AM_CFLAGS} -Werror ${SODIUM_CFLAGS} ${UUID_CFLAGS}" -AM_LDFLAGS="${AM_LDFLAGS} ${SODIUM_LIBS} ${UUID_LIBS}" - -AC_CONFIG_FILES([Makefile - test/Makefile - libks.pc -]) - -AC_OUTPUT diff --git a/libs/libks/crypt/aes.h b/libs/libks/crypt/aes.h deleted file mode 100644 index e05d58b826..0000000000 --- a/libs/libks/crypt/aes.h +++ /dev/null @@ -1,198 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the definitions required to use AES in C. See aesopt.h - for optimisation details. -*/ - -#ifndef _AES_H -#define _AES_H - -#include - -/* This include is used to find 8 & 32 bit unsigned integer types */ -#include "brg_types.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#define AES_128 /* if a fast 128 bit key scheduler is needed */ -#define AES_192 /* if a fast 192 bit key scheduler is needed */ -#define AES_256 /* if a fast 256 bit key scheduler is needed */ -#define AES_VAR /* if variable key size scheduler is needed */ -#define AES_MODES /* if support is needed for modes */ - -/* The following must also be set in assembler files if being used */ - -#define AES_ENCRYPT /* if support for encryption is needed */ -#define AES_DECRYPT /* if support for decryption is needed */ -#define AES_REV_DKS /* define to reverse decryption key schedule */ - -#define AES_BLOCK_SIZE 16 /* the AES block size in bytes */ -#define N_COLS 4 /* the number of columns in the state */ - -/* The key schedule length is 11, 13 or 15 16-byte blocks for 128, */ -/* 192 or 256-bit keys respectively. That is 176, 208 or 240 bytes */ -/* or 44, 52 or 60 32-bit words. */ - -#if defined( AES_VAR ) || defined( AES_256 ) -#define KS_LENGTH 60 -#elif defined( AES_192 ) -#define KS_LENGTH 52 -#else -#define KS_LENGTH 44 -#endif - -#define AES_RETURN INT_RETURN - -/* the character array 'inf' in the following structures is used */ -/* to hold AES context information. This AES code uses cx->inf.b[0] */ -/* to hold the number of rounds multiplied by 16. The other three */ -/* elements can be used by code that implements additional modes */ - -typedef union -{ uint_32t l; - uint_8t b[4]; -} aes_inf; - -typedef struct -{ uint_32t ks[KS_LENGTH]; - aes_inf inf; -} aes_encrypt_ctx; - -typedef struct -{ uint_32t ks[KS_LENGTH]; - aes_inf inf; -} aes_decrypt_ctx; - -/* This routine must be called before first use if non-static */ -/* tables are being used */ - -AES_RETURN ks_aes_init(void); - -/* Key lengths in the range 16 <= key_len <= 32 are given in bytes, */ -/* those in the range 128 <= key_len <= 256 are given in bits */ - -#if defined( AES_ENCRYPT ) - -#if defined( AES_128 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_192 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_256 ) || defined( AES_VAR) -AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); -#endif - -#if defined( AES_VAR ) -AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]); -#endif - -AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]); - -#endif - -#if defined( AES_DECRYPT ) - -#if defined( AES_128 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_192 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_256 ) || defined( AES_VAR) -AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); -#endif - -#if defined( AES_VAR ) -AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]); -#endif - -AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]); - -#endif - -#if defined( AES_MODES ) - -/* Multiple calls to the following subroutines for multiple block */ -/* ECB, CBC, CFB, OFB and CTR mode encryption can be used to handle */ -/* long messages incremantally provided that the context AND the iv */ -/* are preserved between all such calls. For the ECB and CBC modes */ -/* each individual call within a series of incremental calls must */ -/* process only full blocks (i.e. len must be a multiple of 16) but */ -/* the CFB, OFB and CTR mode calls can handle multiple incremental */ -/* calls of any length. Each mode is reset when a new AES key is */ -/* set but ECB and CBC operations can be reset without setting a */ -/* new key by setting a new IV value. To reset CFB, OFB and CTR */ -/* without setting the key, aes_mode_reset() must be called and the */ -/* IV must be set. NOTE: All these calls update the IV on exit so */ -/* this has to be reset if a new operation with the same IV as the */ -/* previous one is required (or decryption follows encryption with */ -/* the same IV array). */ - -AES_RETURN aes_test_alignment_detection(unsigned int n); - -AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_encrypt_ctx cx[1]); - -AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_decrypt_ctx cx[1]); - -AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_decrypt_ctx cx[1]); - -AES_RETURN aes_mode_reset(aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -#define aes_ofb_encrypt aes_ofb_crypt -#define aes_ofb_decrypt aes_ofb_crypt - -AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx cx[1]); - -typedef void cbuf_inc(unsigned char *cbuf); - -#define aes_ctr_encrypt aes_ctr_crypt -#define aes_ctr_decrypt aes_ctr_crypt - -AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx cx[1]); - -#endif - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/libs/libks/crypt/aes_modes.c b/libs/libks/crypt/aes_modes.c deleted file mode 100644 index 2ffa783bf3..0000000000 --- a/libs/libks/crypt/aes_modes.c +++ /dev/null @@ -1,946 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - These subroutines implement multiple block AES modes for ECB, CBC, CFB, - OFB and CTR encryption, The code provides support for the VIA Advanced - Cryptography Engine (ACE). - - NOTE: In the following subroutines, the AES contexts (ctx) must be - 16 byte aligned if VIA ACE is being used -*/ - -#include -#include - -#include "aesopt.h" - -#if defined( AES_MODES ) -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) -#pragma intrinsic(memcpy) -#endif - -#define BFR_BLOCKS 8 - -/* These values are used to detect long word alignment in order to */ -/* speed up some buffer operations. This facility may not work on */ -/* some machines so this define can be commented out if necessary */ - -#define FAST_BUFFER_OPERATIONS - -#define lp32(x) ((uint_32t*)(x)) - -#if defined( USE_VIA_ACE_IF_PRESENT ) - -#include "aes_via_ace.h" - -#pragma pack(16) - -aligned_array(unsigned long, enc_gen_table, 12, 16) = NEH_ENC_GEN_DATA; -aligned_array(unsigned long, enc_load_table, 12, 16) = NEH_ENC_LOAD_DATA; -aligned_array(unsigned long, enc_hybrid_table, 12, 16) = NEH_ENC_HYBRID_DATA; -aligned_array(unsigned long, dec_gen_table, 12, 16) = NEH_DEC_GEN_DATA; -aligned_array(unsigned long, dec_load_table, 12, 16) = NEH_DEC_LOAD_DATA; -aligned_array(unsigned long, dec_hybrid_table, 12, 16) = NEH_DEC_HYBRID_DATA; - -/* NOTE: These control word macros must only be used after */ -/* a key has been set up because they depend on key size */ -/* See the VIA ACE documentation for key type information */ -/* and aes_via_ace.h for non-default NEH_KEY_TYPE values */ - -#ifndef NEH_KEY_TYPE -# define NEH_KEY_TYPE NEH_HYBRID -#endif - -#if NEH_KEY_TYPE == NEH_LOAD -#define kd_adr(c) ((uint_8t*)(c)->ks) -#elif NEH_KEY_TYPE == NEH_GENERATE -#define kd_adr(c) ((uint_8t*)(c)->ks + (c)->inf.b[0]) -#elif NEH_KEY_TYPE == NEH_HYBRID -#define kd_adr(c) ((uint_8t*)(c)->ks + ((c)->inf.b[0] == 160 ? 160 : 0)) -#else -#error no key type defined for VIA ACE -#endif - -#else - -#define aligned_array(type, name, no, stride) type name[no] -#define aligned_auto(type, name, no, stride) type name[no] - -#endif - -#if defined( _MSC_VER ) && _MSC_VER > 1200 - -#define via_cwd(cwd, ty, dir, len) \ - unsigned long* cwd = (dir##_##ty##_table + ((len - 128) >> 4)) - -#else - -#define via_cwd(cwd, ty, dir, len) \ - aligned_auto(unsigned long, cwd, 4, 16); \ - cwd[1] = cwd[2] = cwd[3] = 0; \ - cwd[0] = neh_##dir##_##ty##_key(len) - -#endif - -/* test the code for detecting and setting pointer alignment */ - -AES_RETURN aes_test_alignment_detection(unsigned int n) /* 4 <= n <= 16 */ -{ uint_8t p[16]; - uint_32t i, count_eq = 0, count_neq = 0; - - if(n < 4 || n > 16) - return EXIT_FAILURE; - - for(i = 0; i < n; ++i) - { - uint_8t *qf = ALIGN_FLOOR(p + i, n), - *qh = ALIGN_CEIL(p + i, n); - - if(qh == qf) - ++count_eq; - else if(qh == qf + n) - ++count_neq; - else - return EXIT_FAILURE; - } - return (count_eq != 1 || count_neq != n - 1 ? EXIT_FAILURE : EXIT_SUCCESS); -} - -AES_RETURN aes_mode_reset(aes_encrypt_ctx ctx[1]) -{ - ctx->inf.b[2] = 0; - return EXIT_SUCCESS; -} - -AES_RETURN aes_ecb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_encrypt_ctx ctx[1]) -{ int nb = len >> 4; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint_8t *ksp = (uint_8t*)(ctx->ks); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_ecb_op5(ksp, cwd, ibuf, obuf, nb); - } - else - { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint_8t *ip, *op; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_ecb_op5(ksp, cwd, ip, op, m); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - return EXIT_SUCCESS; - } - -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) - while(nb--) - { - if(aes_encrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_ecb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, const aes_decrypt_ctx ctx[1]) -{ int nb = len >> 4; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint_8t *ksp = kd_adr(ctx); - via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_ecb_op5(ksp, cwd, ibuf, obuf, nb); - } - else - { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint_8t *ip, *op; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_ecb_op5(ksp, cwd, ip, op, m); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - return EXIT_SUCCESS; - } - -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) - while(nb--) - { - if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_cbc_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_encrypt_ctx ctx[1]) -{ int nb = len >> 4; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; - aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) - { - via_cbc_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); - } - else - { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint_8t *ip, *op; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cbc_op7(ksp, cwd, ip, op, m, ivp, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - if(iv != ivp) - memcpy(iv, ivp, AES_BLOCK_SIZE); - - return EXIT_SUCCESS; - } - -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(nb--) - { - lp32(iv)[0] ^= lp32(ibuf)[0]; - lp32(iv)[1] ^= lp32(ibuf)[1]; - lp32(iv)[2] ^= lp32(ibuf)[2]; - lp32(iv)[3] ^= lp32(ibuf)[3]; - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - memcpy(obuf, iv, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - else -# endif - while(nb--) - { - iv[ 0] ^= ibuf[ 0]; iv[ 1] ^= ibuf[ 1]; - iv[ 2] ^= ibuf[ 2]; iv[ 3] ^= ibuf[ 3]; - iv[ 4] ^= ibuf[ 4]; iv[ 5] ^= ibuf[ 5]; - iv[ 6] ^= ibuf[ 6]; iv[ 7] ^= ibuf[ 7]; - iv[ 8] ^= ibuf[ 8]; iv[ 9] ^= ibuf[ 9]; - iv[10] ^= ibuf[10]; iv[11] ^= ibuf[11]; - iv[12] ^= ibuf[12]; iv[13] ^= ibuf[13]; - iv[14] ^= ibuf[14]; iv[15] ^= ibuf[15]; - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - memcpy(obuf, iv, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_cbc_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, const aes_decrypt_ctx ctx[1]) -{ unsigned char tmp[AES_BLOCK_SIZE]; - int nb = len >> 4; - - if(len & (AES_BLOCK_SIZE - 1)) - return EXIT_FAILURE; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { uint_8t *ksp = kd_adr(ctx), *ivp = iv; - aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 ) && !ALIGN_OFFSET( iv, 16 )) - { - via_cbc_op6(ksp, cwd, ibuf, obuf, nb, ivp); - } - else - { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint_8t *ip, *op; - - while(nb) - { - int m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb); - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cbc_op6(ksp, cwd, ip, op, m, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - nb -= m; - } - } - - if(iv != ivp) - memcpy(iv, ivp, AES_BLOCK_SIZE); - - return EXIT_SUCCESS; - } -#endif - -#if !defined( ASSUME_VIA_ACE_PRESENT ) -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(nb--) - { - memcpy(tmp, ibuf, AES_BLOCK_SIZE); - if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - lp32(obuf)[0] ^= lp32(iv)[0]; - lp32(obuf)[1] ^= lp32(iv)[1]; - lp32(obuf)[2] ^= lp32(iv)[2]; - lp32(obuf)[3] ^= lp32(iv)[3]; - memcpy(iv, tmp, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - else -# endif - while(nb--) - { - memcpy(tmp, ibuf, AES_BLOCK_SIZE); - if(aes_decrypt(ibuf, obuf, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - obuf[ 0] ^= iv[ 0]; obuf[ 1] ^= iv[ 1]; - obuf[ 2] ^= iv[ 2]; obuf[ 3] ^= iv[ 3]; - obuf[ 4] ^= iv[ 4]; obuf[ 5] ^= iv[ 5]; - obuf[ 6] ^= iv[ 6]; obuf[ 7] ^= iv[ 7]; - obuf[ 8] ^= iv[ 8]; obuf[ 9] ^= iv[ 9]; - obuf[10] ^= iv[10]; obuf[11] ^= iv[11]; - obuf[12] ^= iv[12]; obuf[13] ^= iv[13]; - obuf[14] ^= iv[14]; obuf[15] ^= iv[15]; - memcpy(iv, tmp, AES_BLOCK_SIZE); - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } -#endif - return EXIT_SUCCESS; -} - -AES_RETURN aes_cfb_encrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) -{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; - - if(b_pos) /* complete any partial block */ - { - while(b_pos < AES_BLOCK_SIZE && cnt < len) - { - *obuf++ = (iv[b_pos++] ^= *ibuf++); - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ - { -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { int m; - uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; - aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_cfb_op7(ksp, cwd, ibuf, obuf, nb, ivp, ivp); - ibuf += nb * AES_BLOCK_SIZE; - obuf += nb * AES_BLOCK_SIZE; - cnt += nb * AES_BLOCK_SIZE; - } - else /* input, output or both are unaligned */ - { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint_8t *ip, *op; - - while(nb) - { - m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cfb_op7(ksp, cwd, ip, op, m, ivp, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - cnt += m * AES_BLOCK_SIZE; - } - } - - if(ivp != iv) - memcpy(iv, ivp, AES_BLOCK_SIZE); - } -#else -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - lp32(obuf)[0] = lp32(iv)[0] ^= lp32(ibuf)[0]; - lp32(obuf)[1] = lp32(iv)[1] ^= lp32(ibuf)[1]; - lp32(obuf)[2] = lp32(iv)[2] ^= lp32(ibuf)[2]; - lp32(obuf)[3] = lp32(iv)[3] ^= lp32(ibuf)[3]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } - else -# endif - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - obuf[ 0] = iv[ 0] ^= ibuf[ 0]; obuf[ 1] = iv[ 1] ^= ibuf[ 1]; - obuf[ 2] = iv[ 2] ^= ibuf[ 2]; obuf[ 3] = iv[ 3] ^= ibuf[ 3]; - obuf[ 4] = iv[ 4] ^= ibuf[ 4]; obuf[ 5] = iv[ 5] ^= ibuf[ 5]; - obuf[ 6] = iv[ 6] ^= ibuf[ 6]; obuf[ 7] = iv[ 7] ^= ibuf[ 7]; - obuf[ 8] = iv[ 8] ^= ibuf[ 8]; obuf[ 9] = iv[ 9] ^= ibuf[ 9]; - obuf[10] = iv[10] ^= ibuf[10]; obuf[11] = iv[11] ^= ibuf[11]; - obuf[12] = iv[12] ^= ibuf[12]; obuf[13] = iv[13] ^= ibuf[13]; - obuf[14] = iv[14] ^= ibuf[14]; obuf[15] = iv[15] ^= ibuf[15]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } -#endif - } - - while(cnt < len) - { - if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(cnt < len && b_pos < AES_BLOCK_SIZE) - { - *obuf++ = (iv[b_pos++] ^= *ibuf++); - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - ctx->inf.b[2] = (uint_8t)b_pos; - return EXIT_SUCCESS; -} - -AES_RETURN aes_cfb_decrypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) -{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; - - if(b_pos) /* complete any partial block */ - { uint_8t t; - - while(b_pos < AES_BLOCK_SIZE && cnt < len) - { - t = *ibuf++; - *obuf++ = t ^ iv[b_pos]; - iv[b_pos++] = t; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ - { -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { int m; - uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; - aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, dec, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_cfb_op6(ksp, cwd, ibuf, obuf, nb, ivp); - ibuf += nb * AES_BLOCK_SIZE; - obuf += nb * AES_BLOCK_SIZE; - cnt += nb * AES_BLOCK_SIZE; - } - else /* input, output or both are unaligned */ - { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint_8t *ip, *op; - - while(nb) - { - m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) /* input buffer is not aligned */ - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_cfb_op6(ksp, cwd, ip, op, m, ivp); - - if(op != obuf) /* output buffer is not aligned */ - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - cnt += m * AES_BLOCK_SIZE; - } - } - - if(ivp != iv) - memcpy(iv, ivp, AES_BLOCK_SIZE); - } -#else -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) &&!ALIGN_OFFSET( iv, 4 )) - while(cnt + AES_BLOCK_SIZE <= len) - { uint_32t t; - - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - t = lp32(ibuf)[0], lp32(obuf)[0] = t ^ lp32(iv)[0], lp32(iv)[0] = t; - t = lp32(ibuf)[1], lp32(obuf)[1] = t ^ lp32(iv)[1], lp32(iv)[1] = t; - t = lp32(ibuf)[2], lp32(obuf)[2] = t ^ lp32(iv)[2], lp32(iv)[2] = t; - t = lp32(ibuf)[3], lp32(obuf)[3] = t ^ lp32(iv)[3], lp32(iv)[3] = t; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } - else -# endif - while(cnt + AES_BLOCK_SIZE <= len) - { uint_8t t; - - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - t = ibuf[ 0], obuf[ 0] = t ^ iv[ 0], iv[ 0] = t; - t = ibuf[ 1], obuf[ 1] = t ^ iv[ 1], iv[ 1] = t; - t = ibuf[ 2], obuf[ 2] = t ^ iv[ 2], iv[ 2] = t; - t = ibuf[ 3], obuf[ 3] = t ^ iv[ 3], iv[ 3] = t; - t = ibuf[ 4], obuf[ 4] = t ^ iv[ 4], iv[ 4] = t; - t = ibuf[ 5], obuf[ 5] = t ^ iv[ 5], iv[ 5] = t; - t = ibuf[ 6], obuf[ 6] = t ^ iv[ 6], iv[ 6] = t; - t = ibuf[ 7], obuf[ 7] = t ^ iv[ 7], iv[ 7] = t; - t = ibuf[ 8], obuf[ 8] = t ^ iv[ 8], iv[ 8] = t; - t = ibuf[ 9], obuf[ 9] = t ^ iv[ 9], iv[ 9] = t; - t = ibuf[10], obuf[10] = t ^ iv[10], iv[10] = t; - t = ibuf[11], obuf[11] = t ^ iv[11], iv[11] = t; - t = ibuf[12], obuf[12] = t ^ iv[12], iv[12] = t; - t = ibuf[13], obuf[13] = t ^ iv[13], iv[13] = t; - t = ibuf[14], obuf[14] = t ^ iv[14], iv[14] = t; - t = ibuf[15], obuf[15] = t ^ iv[15], iv[15] = t; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } -#endif - } - - while(cnt < len) - { uint_8t t; - - if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(cnt < len && b_pos < AES_BLOCK_SIZE) - { - t = *ibuf++; - *obuf++ = t ^ iv[b_pos]; - iv[b_pos++] = t; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - ctx->inf.b[2] = (uint_8t)b_pos; - return EXIT_SUCCESS; -} - -AES_RETURN aes_ofb_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *iv, aes_encrypt_ctx ctx[1]) -{ int cnt = 0, b_pos = (int)ctx->inf.b[2], nb; - - if(b_pos) /* complete any partial block */ - { - while(b_pos < AES_BLOCK_SIZE && cnt < len) - { - *obuf++ = iv[b_pos++] ^ *ibuf++; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - if((nb = (len - cnt) >> 4) != 0) /* process whole blocks */ - { -#if defined( USE_VIA_ACE_IF_PRESENT ) - - if(ctx->inf.b[1] == 0xff) - { int m; - uint_8t *ksp = (uint_8t*)(ctx->ks), *ivp = iv; - aligned_auto(uint_8t, liv, AES_BLOCK_SIZE, 16); - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - - if(ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; - - if(ALIGN_OFFSET( iv, 16 )) /* ensure an aligned iv */ - { - ivp = liv; - memcpy(liv, iv, AES_BLOCK_SIZE); - } - - if(!ALIGN_OFFSET( ibuf, 16 ) && !ALIGN_OFFSET( obuf, 16 )) - { - via_ofb_op6(ksp, cwd, ibuf, obuf, nb, ivp); - ibuf += nb * AES_BLOCK_SIZE; - obuf += nb * AES_BLOCK_SIZE; - cnt += nb * AES_BLOCK_SIZE; - } - else /* input, output or both are unaligned */ - { aligned_auto(uint_8t, buf, BFR_BLOCKS * AES_BLOCK_SIZE, 16); - uint_8t *ip, *op; - - while(nb) - { - m = (nb > BFR_BLOCKS ? BFR_BLOCKS : nb), nb -= m; - - ip = (ALIGN_OFFSET( ibuf, 16 ) ? buf : ibuf); - op = (ALIGN_OFFSET( obuf, 16 ) ? buf : obuf); - - if(ip != ibuf) - memcpy(buf, ibuf, m * AES_BLOCK_SIZE); - - via_ofb_op6(ksp, cwd, ip, op, m, ivp); - - if(op != obuf) - memcpy(obuf, buf, m * AES_BLOCK_SIZE); - - ibuf += m * AES_BLOCK_SIZE; - obuf += m * AES_BLOCK_SIZE; - cnt += m * AES_BLOCK_SIZE; - } - } - - if(ivp != iv) - memcpy(iv, ivp, AES_BLOCK_SIZE); - } -#else -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( iv, 4 )) - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - lp32(obuf)[0] = lp32(iv)[0] ^ lp32(ibuf)[0]; - lp32(obuf)[1] = lp32(iv)[1] ^ lp32(ibuf)[1]; - lp32(obuf)[2] = lp32(iv)[2] ^ lp32(ibuf)[2]; - lp32(obuf)[3] = lp32(iv)[3] ^ lp32(ibuf)[3]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } - else -# endif - while(cnt + AES_BLOCK_SIZE <= len) - { - assert(b_pos == 0); - if(aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - obuf[ 0] = iv[ 0] ^ ibuf[ 0]; obuf[ 1] = iv[ 1] ^ ibuf[ 1]; - obuf[ 2] = iv[ 2] ^ ibuf[ 2]; obuf[ 3] = iv[ 3] ^ ibuf[ 3]; - obuf[ 4] = iv[ 4] ^ ibuf[ 4]; obuf[ 5] = iv[ 5] ^ ibuf[ 5]; - obuf[ 6] = iv[ 6] ^ ibuf[ 6]; obuf[ 7] = iv[ 7] ^ ibuf[ 7]; - obuf[ 8] = iv[ 8] ^ ibuf[ 8]; obuf[ 9] = iv[ 9] ^ ibuf[ 9]; - obuf[10] = iv[10] ^ ibuf[10]; obuf[11] = iv[11] ^ ibuf[11]; - obuf[12] = iv[12] ^ ibuf[12]; obuf[13] = iv[13] ^ ibuf[13]; - obuf[14] = iv[14] ^ ibuf[14]; obuf[15] = iv[15] ^ ibuf[15]; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - cnt += AES_BLOCK_SIZE; - } -#endif - } - - while(cnt < len) - { - if(!b_pos && aes_encrypt(iv, iv, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(cnt < len && b_pos < AES_BLOCK_SIZE) - { - *obuf++ = iv[b_pos++] ^ *ibuf++; - cnt++; - } - - b_pos = (b_pos == AES_BLOCK_SIZE ? 0 : b_pos); - } - - ctx->inf.b[2] = (uint_8t)b_pos; - return EXIT_SUCCESS; -} - -#define BFR_LENGTH (BFR_BLOCKS * AES_BLOCK_SIZE) - -AES_RETURN aes_ctr_crypt(const unsigned char *ibuf, unsigned char *obuf, - int len, unsigned char *cbuf, cbuf_inc ctr_inc, aes_encrypt_ctx ctx[1]) -{ unsigned char *ip; - int i, blen, b_pos = (int)(ctx->inf.b[2]); - -#if defined( USE_VIA_ACE_IF_PRESENT ) - aligned_auto(uint_8t, buf, BFR_LENGTH, 16); - if(ctx->inf.b[1] == 0xff && ALIGN_OFFSET( ctx, 16 )) - return EXIT_FAILURE; -#else - uint_8t buf[BFR_LENGTH]; -#endif - - if(b_pos) - { - memcpy(buf, cbuf, AES_BLOCK_SIZE); - if(aes_ecb_encrypt(buf, buf, AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - while(b_pos < AES_BLOCK_SIZE && len) - { - *obuf++ = *ibuf++ ^ buf[b_pos++]; - --len; - } - - if(len) - ctr_inc(cbuf), b_pos = 0; - } - - while(len) - { - blen = (len > BFR_LENGTH ? BFR_LENGTH : len), len -= blen; - - for(i = 0, ip = buf; i < (blen >> 4); ++i) - { - memcpy(ip, cbuf, AES_BLOCK_SIZE); - ctr_inc(cbuf); - ip += AES_BLOCK_SIZE; - } - - if(blen & (AES_BLOCK_SIZE - 1)) - memcpy(ip, cbuf, AES_BLOCK_SIZE), i++; - -#if defined( USE_VIA_ACE_IF_PRESENT ) - if(ctx->inf.b[1] == 0xff) - { - via_cwd(cwd, hybrid, enc, 2 * ctx->inf.b[0] - 192); - via_ecb_op5((ctx->ks), cwd, buf, buf, i); - } - else -#endif - if(aes_ecb_encrypt(buf, buf, i * AES_BLOCK_SIZE, ctx) != EXIT_SUCCESS) - return EXIT_FAILURE; - - i = 0; ip = buf; -# ifdef FAST_BUFFER_OPERATIONS - if(!ALIGN_OFFSET( ibuf, 4 ) && !ALIGN_OFFSET( obuf, 4 ) && !ALIGN_OFFSET( ip, 4 )) - while(i + AES_BLOCK_SIZE <= blen) - { - lp32(obuf)[0] = lp32(ibuf)[0] ^ lp32(ip)[0]; - lp32(obuf)[1] = lp32(ibuf)[1] ^ lp32(ip)[1]; - lp32(obuf)[2] = lp32(ibuf)[2] ^ lp32(ip)[2]; - lp32(obuf)[3] = lp32(ibuf)[3] ^ lp32(ip)[3]; - i += AES_BLOCK_SIZE; - ip += AES_BLOCK_SIZE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - else -#endif - while(i + AES_BLOCK_SIZE <= blen) - { - obuf[ 0] = ibuf[ 0] ^ ip[ 0]; obuf[ 1] = ibuf[ 1] ^ ip[ 1]; - obuf[ 2] = ibuf[ 2] ^ ip[ 2]; obuf[ 3] = ibuf[ 3] ^ ip[ 3]; - obuf[ 4] = ibuf[ 4] ^ ip[ 4]; obuf[ 5] = ibuf[ 5] ^ ip[ 5]; - obuf[ 6] = ibuf[ 6] ^ ip[ 6]; obuf[ 7] = ibuf[ 7] ^ ip[ 7]; - obuf[ 8] = ibuf[ 8] ^ ip[ 8]; obuf[ 9] = ibuf[ 9] ^ ip[ 9]; - obuf[10] = ibuf[10] ^ ip[10]; obuf[11] = ibuf[11] ^ ip[11]; - obuf[12] = ibuf[12] ^ ip[12]; obuf[13] = ibuf[13] ^ ip[13]; - obuf[14] = ibuf[14] ^ ip[14]; obuf[15] = ibuf[15] ^ ip[15]; - i += AES_BLOCK_SIZE; - ip += AES_BLOCK_SIZE; - ibuf += AES_BLOCK_SIZE; - obuf += AES_BLOCK_SIZE; - } - - while(i++ < blen) - *obuf++ = *ibuf++ ^ ip[b_pos++]; - } - - ctx->inf.b[2] = (uint_8t)b_pos; - return EXIT_SUCCESS; -} - -#if defined(__cplusplus) -} -#endif -#endif diff --git a/libs/libks/crypt/aescpp.h b/libs/libks/crypt/aescpp.h deleted file mode 100644 index e283cfa550..0000000000 --- a/libs/libks/crypt/aescpp.h +++ /dev/null @@ -1,141 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the definitions required to use AES (Rijndael) in C++. -*/ - -#ifndef _AESCPP_H -#define _AESCPP_H - -#include "aes.h" - -#if defined( AES_ENCRYPT ) - -class AESencrypt -{ -public: - aes_encrypt_ctx cx[1]; - AESencrypt(void) { aes_init_zrtp(); }; -#if defined(AES_128) - AESencrypt(const unsigned char key[]) - { aes_encrypt_key128(key, cx); } - AES_RETURN key128(const unsigned char key[]) - { return aes_encrypt_key128(key, cx); } -#endif -#if defined(AES_192) - AES_RETURN key192(const unsigned char key[]) - { return aes_encrypt_key192(key, cx); } -#endif -#if defined(AES_256) - AES_RETURN key256(const unsigned char key[]) - { return aes_encrypt_key256(key, cx); } -#endif -#if defined(AES_VAR) - AES_RETURN key(const unsigned char key[], int key_len) - { return aes_encrypt_key(key, key_len, cx); } -#endif - AES_RETURN encrypt(const unsigned char in[], unsigned char out[]) const - { return aes_encrypt(in, out, cx); } -#ifndef AES_MODES - AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const - { while(nb--) - { aes_encrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; } - } -#endif -#ifdef AES_MODES - AES_RETURN mode_reset(void) { return aes_mode_reset(cx); } - - AES_RETURN ecb_encrypt(const unsigned char in[], unsigned char out[], int nb) const - { return aes_ecb_encrypt(in, out, nb, cx); } - - AES_RETURN cbc_encrypt(const unsigned char in[], unsigned char out[], int nb, - unsigned char iv[]) const - { return aes_cbc_encrypt(in, out, nb, iv, cx); } - - AES_RETURN cfb_encrypt(const unsigned char in[], unsigned char out[], int nb, - unsigned char iv[]) - { return aes_cfb_encrypt(in, out, nb, iv, cx); } - - AES_RETURN cfb_decrypt(const unsigned char in[], unsigned char out[], int nb, - unsigned char iv[]) - { return aes_cfb_decrypt(in, out, nb, iv, cx); } - - AES_RETURN ofb_crypt(const unsigned char in[], unsigned char out[], int nb, - unsigned char iv[]) - { return aes_ofb_crypt(in, out, nb, iv, cx); } - - typedef void ctr_fn(unsigned char ctr[]); - - AES_RETURN ctr_crypt(const unsigned char in[], unsigned char out[], int nb, - unsigned char iv[], ctr_fn cf) - { return aes_ctr_crypt(in, out, nb, iv, cf, cx); } - -#endif - -}; - -#endif - -#if defined( AES_DECRYPT ) - -class AESdecrypt -{ -public: - aes_decrypt_ctx cx[1]; - AESdecrypt(void) { aes_init_zrtp(); }; -#if defined(AES_128) - AESdecrypt(const unsigned char key[]) - { aes_decrypt_key128(key, cx); } - AES_RETURN key128(const unsigned char key[]) - { return aes_decrypt_key128(key, cx); } -#endif -#if defined(AES_192) - AES_RETURN key192(const unsigned char key[]) - { return aes_decrypt_key192(key, cx); } -#endif -#if defined(AES_256) - AES_RETURN key256(const unsigned char key[]) - { return aes_decrypt_key256(key, cx); } -#endif -#if defined(AES_VAR) - AES_RETURN key(const unsigned char key[], int key_len) - { return aes_decrypt_key(key, key_len, cx); } -#endif - AES_RETURN decrypt(const unsigned char in[], unsigned char out[]) const - { return aes_decrypt(in, out, cx); } -#ifndef AES_MODES - AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const - { while(nb--) - { aes_decrypt(in, out, cx), in += AES_BLOCK_SIZE, out += AES_BLOCK_SIZE; } - } -#endif -#ifdef AES_MODES - - AES_RETURN ecb_decrypt(const unsigned char in[], unsigned char out[], int nb) const - { return aes_ecb_decrypt(in, out, nb, cx); } - - AES_RETURN cbc_decrypt(const unsigned char in[], unsigned char out[], int nb, - unsigned char iv[]) const - { return aes_cbc_decrypt(in, out, nb, iv, cx); } -#endif -}; - -#endif - -#endif diff --git a/libs/libks/crypt/aescrypt.c b/libs/libks/crypt/aescrypt.c deleted file mode 100644 index 6095f41a68..0000000000 --- a/libs/libks/crypt/aescrypt.c +++ /dev/null @@ -1,294 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#include "aesopt.h" -#include "aestab.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#define si(y,x,k,c) (s(y,c) = word_in(x, c) ^ (k)[c]) -#define so(y,x,c) word_out(y, c, s(x,c)) - -#if defined(ARRAYS) -#define locals(y,x) x[4],y[4] -#else -#define locals(y,x) x##0,x##1,x##2,x##3,y##0,y##1,y##2,y##3 -#endif - -#define l_copy(y, x) s(y,0) = s(x,0); s(y,1) = s(x,1); \ - s(y,2) = s(x,2); s(y,3) = s(x,3); -#define state_in(y,x,k) si(y,x,k,0); si(y,x,k,1); si(y,x,k,2); si(y,x,k,3) -#define state_out(y,x) so(y,x,0); so(y,x,1); so(y,x,2); so(y,x,3) -#define round(rm,y,x,k) rm(y,x,k,0); rm(y,x,k,1); rm(y,x,k,2); rm(y,x,k,3) - -#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) - -/* Visual C++ .Net v7.1 provides the fastest encryption code when using - Pentium optimiation with small code but this is poor for decryption - so we need to control this with the following VC++ pragmas -*/ - -#if defined( _MSC_VER ) && !defined( _WIN64 ) -#pragma optimize( "s", on ) -#endif - -/* Given the column (c) of the output state variable, the following - macros give the input state variables which are needed in its - computation for each row (r) of the state. All the alternative - macros give the same end values but expand into different ways - of calculating these values. In particular the complex macro - used for dynamically variable block sizes is designed to expand - to a compile time constant whenever possible but will expand to - conditional clauses on some branches (I am grateful to Frank - Yellin for this construction) -*/ - -#define fwd_var(x,r,c)\ - ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ - : r == 1 ? ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))\ - : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ - : ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))) - -#if defined(FT4_SET) -#undef dec_fmvars -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,n),fwd_var,rf1,c)) -#elif defined(FT1_SET) -#undef dec_fmvars -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(f,n),fwd_var,rf1,c)) -#else -#define fwd_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ fwd_mcol(no_table(x,t_use(s,box),fwd_var,rf1,c))) -#endif - -#if defined(FL4_SET) -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(f,l),fwd_var,rf1,c)) -#elif defined(FL1_SET) -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(f,l),fwd_var,rf1,c)) -#else -#define fwd_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(s,box),fwd_var,rf1,c)) -#endif - -AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, const aes_encrypt_ctx cx[1]) -{ uint_32t locals(b0, b1); - const uint_32t *kp; -#if defined( dec_fmvars ) - dec_fmvars; /* declare variables for fwd_mcol() if needed */ -#endif - - if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) - return EXIT_FAILURE; - - kp = cx->ks; - state_in(b0, in, kp); - -#if (ENC_UNROLL == FULL) - - switch(cx->inf.b[0]) - { - case 14 * 16: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - kp += 2 * N_COLS; - case 12 * 16: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - kp += 2 * N_COLS; - case 10 * 16: - round(fwd_rnd, b1, b0, kp + 1 * N_COLS); - round(fwd_rnd, b0, b1, kp + 2 * N_COLS); - round(fwd_rnd, b1, b0, kp + 3 * N_COLS); - round(fwd_rnd, b0, b1, kp + 4 * N_COLS); - round(fwd_rnd, b1, b0, kp + 5 * N_COLS); - round(fwd_rnd, b0, b1, kp + 6 * N_COLS); - round(fwd_rnd, b1, b0, kp + 7 * N_COLS); - round(fwd_rnd, b0, b1, kp + 8 * N_COLS); - round(fwd_rnd, b1, b0, kp + 9 * N_COLS); - round(fwd_lrnd, b0, b1, kp +10 * N_COLS); - } - -#else - -#if (ENC_UNROLL == PARTIAL) - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) - { - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); - kp += N_COLS; - round(fwd_rnd, b0, b1, kp); - } - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); -#else - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) - { - kp += N_COLS; - round(fwd_rnd, b1, b0, kp); - l_copy(b0, b1); - } -#endif - kp += N_COLS; - round(fwd_lrnd, b0, b1, kp); - } -#endif - - state_out(out, b0); - return EXIT_SUCCESS; -} - -#endif - -#if ( FUNCS_IN_C & DECRYPTION_IN_C) - -/* Visual C++ .Net v7.1 provides the fastest encryption code when using - Pentium optimiation with small code but this is poor for decryption - so we need to control this with the following VC++ pragmas -*/ - -#if defined( _MSC_VER ) && !defined( _WIN64 ) -#pragma optimize( "t", on ) -#endif - -/* Given the column (c) of the output state variable, the following - macros give the input state variables which are needed in its - computation for each row (r) of the state. All the alternative - macros give the same end values but expand into different ways - of calculating these values. In particular the complex macro - used for dynamically variable block sizes is designed to expand - to a compile time constant whenever possible but will expand to - conditional clauses on some branches (I am grateful to Frank - Yellin for this construction) -*/ - -#define inv_var(x,r,c)\ - ( r == 0 ? ( c == 0 ? s(x,0) : c == 1 ? s(x,1) : c == 2 ? s(x,2) : s(x,3))\ - : r == 1 ? ( c == 0 ? s(x,3) : c == 1 ? s(x,0) : c == 2 ? s(x,1) : s(x,2))\ - : r == 2 ? ( c == 0 ? s(x,2) : c == 1 ? s(x,3) : c == 2 ? s(x,0) : s(x,1))\ - : ( c == 0 ? s(x,1) : c == 1 ? s(x,2) : c == 2 ? s(x,3) : s(x,0))) - -#if defined(IT4_SET) -#undef dec_imvars -#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,n),inv_var,rf1,c)) -#elif defined(IT1_SET) -#undef dec_imvars -#define inv_rnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,upr,t_use(i,n),inv_var,rf1,c)) -#else -#define inv_rnd(y,x,k,c) (s(y,c) = inv_mcol((k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c))) -#endif - -#if defined(IL4_SET) -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ four_tables(x,t_use(i,l),inv_var,rf1,c)) -#elif defined(IL1_SET) -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ one_table(x,ups,t_use(i,l),inv_var,rf1,c)) -#else -#define inv_lrnd(y,x,k,c) (s(y,c) = (k)[c] ^ no_table(x,t_use(i,box),inv_var,rf1,c)) -#endif - -/* This code can work with the decryption key schedule in the */ -/* order that is used for encrytpion (where the 1st decryption */ -/* round key is at the high end ot the schedule) or with a key */ -/* schedule that has been reversed to put the 1st decryption */ -/* round key at the low end of the schedule in memory (when */ -/* AES_REV_DKS is defined) */ - -#ifdef AES_REV_DKS -#define key_ofs 0 -#define rnd_key(n) (kp + n * N_COLS) -#else -#define key_ofs 1 -#define rnd_key(n) (kp - n * N_COLS) -#endif - -AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, const aes_decrypt_ctx cx[1]) -{ uint_32t locals(b0, b1); -#if defined( dec_imvars ) - dec_imvars; /* declare variables for inv_mcol() if needed */ -#endif - const uint_32t *kp; - - if( cx->inf.b[0] != 10 * 16 && cx->inf.b[0] != 12 * 16 && cx->inf.b[0] != 14 * 16 ) - return EXIT_FAILURE; - - kp = cx->ks + (key_ofs ? (cx->inf.b[0] >> 2) : 0); - state_in(b0, in, kp); - -#if (DEC_UNROLL == FULL) - - kp = cx->ks + (key_ofs ? 0 : (cx->inf.b[0] >> 2)); - switch(cx->inf.b[0]) - { - case 14 * 16: - round(inv_rnd, b1, b0, rnd_key(-13)); - round(inv_rnd, b0, b1, rnd_key(-12)); - case 12 * 16: - round(inv_rnd, b1, b0, rnd_key(-11)); - round(inv_rnd, b0, b1, rnd_key(-10)); - case 10 * 16: - round(inv_rnd, b1, b0, rnd_key(-9)); - round(inv_rnd, b0, b1, rnd_key(-8)); - round(inv_rnd, b1, b0, rnd_key(-7)); - round(inv_rnd, b0, b1, rnd_key(-6)); - round(inv_rnd, b1, b0, rnd_key(-5)); - round(inv_rnd, b0, b1, rnd_key(-4)); - round(inv_rnd, b1, b0, rnd_key(-3)); - round(inv_rnd, b0, b1, rnd_key(-2)); - round(inv_rnd, b1, b0, rnd_key(-1)); - round(inv_lrnd, b0, b1, rnd_key( 0)); - } - -#else - -#if (DEC_UNROLL == PARTIAL) - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 5) - 1; ++rnd) - { - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); - kp = rnd_key(1); - round(inv_rnd, b0, b1, kp); - } - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); -#else - { uint_32t rnd; - for(rnd = 0; rnd < (cx->inf.b[0] >> 4) - 1; ++rnd) - { - kp = rnd_key(1); - round(inv_rnd, b1, b0, kp); - l_copy(b0, b1); - } -#endif - kp = rnd_key(1); - round(inv_lrnd, b0, b1, kp); - } -#endif - - state_out(out, b0); - return EXIT_SUCCESS; -} - -#endif - -#if defined(__cplusplus) -} -#endif diff --git a/libs/libks/crypt/aeskey.c b/libs/libks/crypt/aeskey.c deleted file mode 100644 index 14b435f8c1..0000000000 --- a/libs/libks/crypt/aeskey.c +++ /dev/null @@ -1,556 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#include "aesopt.h" -#include "aestab.h" - -/* -#ifdef USE_VIA_ACE_IF_PRESENT -# include "aes_via_ace.h" -#endif -*/ - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* Initialise the key schedule from the user supplied key. The key - length can be specified in bytes, with legal values of 16, 24 - and 32, or in bits, with legal values of 128, 192 and 256. These - values correspond with Nk values of 4, 6 and 8 respectively. - - The following macros implement a single cycle in the key - schedule generation process. The number of cycles needed - for each cx->n_col and nk value is: - - nk = 4 5 6 7 8 - ------------------------------ - cx->n_col = 4 10 9 8 7 7 - cx->n_col = 5 14 11 10 9 9 - cx->n_col = 6 19 15 12 11 11 - cx->n_col = 7 21 19 16 13 14 - cx->n_col = 8 29 23 19 17 14 -*/ - -#if defined( REDUCE_CODE_SIZE ) -# define ls_box ls_sub - uint_32t ls_sub(const uint_32t t, const uint_32t n); -# define inv_mcol im_sub - uint_32t im_sub(const uint_32t x); -# ifdef ENC_KS_UNROLL -# undef ENC_KS_UNROLL -# endif -# ifdef DEC_KS_UNROLL -# undef DEC_KS_UNROLL -# endif -#endif - -#if (FUNCS_IN_C & ENC_KEYING_IN_C) - -#if defined(AES_128) || defined( AES_VAR ) - -#define ke4(k,i) \ -{ k[4*(i)+4] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - k[4*(i)+5] = ss[1] ^= ss[0]; \ - k[4*(i)+6] = ss[2] ^= ss[1]; \ - k[4*(i)+7] = ss[3] ^= ss[2]; \ -} - -AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint_32t ss[4]; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - -#ifdef ENC_KS_UNROLL - ke4(cx->ks, 0); ke4(cx->ks, 1); - ke4(cx->ks, 2); ke4(cx->ks, 3); - ke4(cx->ks, 4); ke4(cx->ks, 5); - ke4(cx->ks, 6); ke4(cx->ks, 7); - ke4(cx->ks, 8); -#else - { uint_32t i; - for(i = 0; i < 9; ++i) - ke4(cx->ks, i); - } -#endif - ke4(cx->ks, 9); - cx->inf.l = 0; - cx->inf.b[0] = 10 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_192) || defined( AES_VAR ) - -#define kef6(k,i) \ -{ k[6*(i)+ 6] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - k[6*(i)+ 7] = ss[1] ^= ss[0]; \ - k[6*(i)+ 8] = ss[2] ^= ss[1]; \ - k[6*(i)+ 9] = ss[3] ^= ss[2]; \ -} - -#define ke6(k,i) \ -{ kef6(k,i); \ - k[6*(i)+10] = ss[4] ^= ss[3]; \ - k[6*(i)+11] = ss[5] ^= ss[4]; \ -} - -AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint_32t ss[6]; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - cx->ks[4] = ss[4] = word_in(key, 4); - cx->ks[5] = ss[5] = word_in(key, 5); - -#ifdef ENC_KS_UNROLL - ke6(cx->ks, 0); ke6(cx->ks, 1); - ke6(cx->ks, 2); ke6(cx->ks, 3); - ke6(cx->ks, 4); ke6(cx->ks, 5); - ke6(cx->ks, 6); -#else - { uint_32t i; - for(i = 0; i < 7; ++i) - ke6(cx->ks, i); - } -#endif - kef6(cx->ks, 7); - cx->inf.l = 0; - cx->inf.b[0] = 12 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_256) || defined( AES_VAR ) - -#define kef8(k,i) \ -{ k[8*(i)+ 8] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - k[8*(i)+ 9] = ss[1] ^= ss[0]; \ - k[8*(i)+10] = ss[2] ^= ss[1]; \ - k[8*(i)+11] = ss[3] ^= ss[2]; \ -} - -#define ke8(k,i) \ -{ kef8(k,i); \ - k[8*(i)+12] = ss[4] ^= ls_box(ss[3],0); \ - k[8*(i)+13] = ss[5] ^= ss[4]; \ - k[8*(i)+14] = ss[6] ^= ss[5]; \ - k[8*(i)+15] = ss[7] ^= ss[6]; \ -} - -AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]) -{ uint_32t ss[8]; - - cx->ks[0] = ss[0] = word_in(key, 0); - cx->ks[1] = ss[1] = word_in(key, 1); - cx->ks[2] = ss[2] = word_in(key, 2); - cx->ks[3] = ss[3] = word_in(key, 3); - cx->ks[4] = ss[4] = word_in(key, 4); - cx->ks[5] = ss[5] = word_in(key, 5); - cx->ks[6] = ss[6] = word_in(key, 6); - cx->ks[7] = ss[7] = word_in(key, 7); - -#ifdef ENC_KS_UNROLL - ke8(cx->ks, 0); ke8(cx->ks, 1); - ke8(cx->ks, 2); ke8(cx->ks, 3); - ke8(cx->ks, 4); ke8(cx->ks, 5); -#else - { uint_32t i; - for(i = 0; i < 6; ++i) - ke8(cx->ks, i); - } -#endif - kef8(cx->ks, 6); - cx->inf.l = 0; - cx->inf.b[0] = 14 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined( AES_VAR ) - -AES_RETURN aes_encrypt_key(const unsigned char *key, int key_len, aes_encrypt_ctx cx[1]) -{ - switch(key_len) - { - case 16: case 128: return aes_encrypt_key128(key, cx); - case 24: case 192: return aes_encrypt_key192(key, cx); - case 32: case 256: return aes_encrypt_key256(key, cx); - default: return EXIT_FAILURE; - } -} - -#endif - -#endif - -#if (FUNCS_IN_C & DEC_KEYING_IN_C) - -/* this is used to store the decryption round keys */ -/* in forward or reverse order */ - -#ifdef AES_REV_DKS -#define v(n,i) ((n) - (i) + 2 * ((i) & 3)) -#else -#define v(n,i) (i) -#endif - -#if DEC_ROUND == NO_TABLES -#define ff(x) (x) -#else -#define ff(x) inv_mcol(x) -#if defined( dec_imvars ) -#define d_vars dec_imvars -#endif -#endif - -#if defined(AES_128) || defined( AES_VAR ) - -#define k4e(k,i) \ -{ k[v(40,(4*(i))+4)] = ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - k[v(40,(4*(i))+5)] = ss[1] ^= ss[0]; \ - k[v(40,(4*(i))+6)] = ss[2] ^= ss[1]; \ - k[v(40,(4*(i))+7)] = ss[3] ^= ss[2]; \ -} - -#if 1 - -#define kdf4(k,i) \ -{ ss[0] = ss[0] ^ ss[2] ^ ss[1] ^ ss[3]; \ - ss[1] = ss[1] ^ ss[3]; \ - ss[2] = ss[2] ^ ss[3]; \ - ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ - ss[i % 4] ^= ss[4]; \ - ss[4] ^= k[v(40,(4*(i)))]; k[v(40,(4*(i))+4)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+1)]; k[v(40,(4*(i))+5)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+2)]; k[v(40,(4*(i))+6)] = ff(ss[4]); \ - ss[4] ^= k[v(40,(4*(i))+3)]; k[v(40,(4*(i))+7)] = ff(ss[4]); \ -} - -#define kd4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; \ - ss[i % 4] ^= ss[4]; ss[4] = ff(ss[4]); \ - k[v(40,(4*(i))+4)] = ss[4] ^= k[v(40,(4*(i)))]; \ - k[v(40,(4*(i))+5)] = ss[4] ^= k[v(40,(4*(i))+1)]; \ - k[v(40,(4*(i))+6)] = ss[4] ^= k[v(40,(4*(i))+2)]; \ - k[v(40,(4*(i))+7)] = ss[4] ^= k[v(40,(4*(i))+3)]; \ -} - -#define kdl4(k,i) \ -{ ss[4] = ls_box(ss[(i+3) % 4], 3) ^ t_use(r,c)[i]; ss[i % 4] ^= ss[4]; \ - k[v(40,(4*(i))+4)] = (ss[0] ^= ss[1]) ^ ss[2] ^ ss[3]; \ - k[v(40,(4*(i))+5)] = ss[1] ^ ss[3]; \ - k[v(40,(4*(i))+6)] = ss[0]; \ - k[v(40,(4*(i))+7)] = ss[1]; \ -} - -#else - -#define kdf4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ff(ss[3]); \ -} - -#define kd4(k,i) \ -{ ss[4] = ls_box(ss[3],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[4]; ss[4] = ff(ss[4]); k[v(40,(4*(i))+ 4)] = ss[4] ^= k[v(40,(4*(i)))]; \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[4] ^= k[v(40,(4*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[4] ^= k[v(40,(4*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[4] ^= k[v(40,(4*(i))+ 3)]; \ -} - -#define kdl4(k,i) \ -{ ss[0] ^= ls_box(ss[3],3) ^ t_use(r,c)[i]; k[v(40,(4*(i))+ 4)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(40,(4*(i))+ 5)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(40,(4*(i))+ 6)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(40,(4*(i))+ 7)] = ss[3]; \ -} - -#endif - -AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint_32t ss[5]; -#if defined( d_vars ) - d_vars; -#endif - cx->ks[v(40,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(40,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(40,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(40,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - kdf4(cx->ks, 0); kd4(cx->ks, 1); - kd4(cx->ks, 2); kd4(cx->ks, 3); - kd4(cx->ks, 4); kd4(cx->ks, 5); - kd4(cx->ks, 6); kd4(cx->ks, 7); - kd4(cx->ks, 8); kdl4(cx->ks, 9); -#else - { uint_32t i; - for(i = 0; i < 10; ++i) - k4e(cx->ks, i); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 10 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 10 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_192) || defined( AES_VAR ) - -#define k6ef(k,i) \ -{ k[v(48,(6*(i))+ 6)] = ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - k[v(48,(6*(i))+ 7)] = ss[1] ^= ss[0]; \ - k[v(48,(6*(i))+ 8)] = ss[2] ^= ss[1]; \ - k[v(48,(6*(i))+ 9)] = ss[3] ^= ss[2]; \ -} - -#define k6e(k,i) \ -{ k6ef(k,i); \ - k[v(48,(6*(i))+10)] = ss[4] ^= ss[3]; \ - k[v(48,(6*(i))+11)] = ss[5] ^= ss[4]; \ -} - -#define kdf6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ff(ss[3]); \ - ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ff(ss[4]); \ - ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ff(ss[5]); \ -} - -#define kd6(k,i) \ -{ ss[6] = ls_box(ss[5],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[6]; ss[6] = ff(ss[6]); k[v(48,(6*(i))+ 6)] = ss[6] ^= k[v(48,(6*(i)))]; \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[6] ^= k[v(48,(6*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[6] ^= k[v(48,(6*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[6] ^= k[v(48,(6*(i))+ 3)]; \ - ss[4] ^= ss[3]; k[v(48,(6*(i))+10)] = ss[6] ^= k[v(48,(6*(i))+ 4)]; \ - ss[5] ^= ss[4]; k[v(48,(6*(i))+11)] = ss[6] ^= k[v(48,(6*(i))+ 5)]; \ -} - -#define kdl6(k,i) \ -{ ss[0] ^= ls_box(ss[5],3) ^ t_use(r,c)[i]; k[v(48,(6*(i))+ 6)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(48,(6*(i))+ 7)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(48,(6*(i))+ 8)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(48,(6*(i))+ 9)] = ss[3]; \ -} - -AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint_32t ss[7]; -#if defined( d_vars ) - d_vars; -#endif - cx->ks[v(48,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(48,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(48,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(48,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - ss[4] = word_in(key, 4); - cx->ks[v(48,(4))] = ff(ss[4]); - ss[5] = word_in(key, 5); - cx->ks[v(48,(5))] = ff(ss[5]); - kdf6(cx->ks, 0); kd6(cx->ks, 1); - kd6(cx->ks, 2); kd6(cx->ks, 3); - kd6(cx->ks, 4); kd6(cx->ks, 5); - kd6(cx->ks, 6); kdl6(cx->ks, 7); -#else - cx->ks[v(48,(4))] = ss[4] = word_in(key, 4); - cx->ks[v(48,(5))] = ss[5] = word_in(key, 5); - { uint_32t i; - - for(i = 0; i < 7; ++i) - k6e(cx->ks, i); - k6ef(cx->ks, 7); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 12 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 12 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined(AES_256) || defined( AES_VAR ) - -#define k8ef(k,i) \ -{ k[v(56,(8*(i))+ 8)] = ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - k[v(56,(8*(i))+ 9)] = ss[1] ^= ss[0]; \ - k[v(56,(8*(i))+10)] = ss[2] ^= ss[1]; \ - k[v(56,(8*(i))+11)] = ss[3] ^= ss[2]; \ -} - -#define k8e(k,i) \ -{ k8ef(k,i); \ - k[v(56,(8*(i))+12)] = ss[4] ^= ls_box(ss[3],0); \ - k[v(56,(8*(i))+13)] = ss[5] ^= ss[4]; \ - k[v(56,(8*(i))+14)] = ss[6] ^= ss[5]; \ - k[v(56,(8*(i))+15)] = ss[7] ^= ss[6]; \ -} - -#define kdf8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ff(ss[0]); \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ff(ss[1]); \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ff(ss[2]); \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ff(ss[3]); \ - ss[4] ^= ls_box(ss[3],0); k[v(56,(8*(i))+12)] = ff(ss[4]); \ - ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ff(ss[5]); \ - ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ff(ss[6]); \ - ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ff(ss[7]); \ -} - -#define kd8(k,i) \ -{ ss[8] = ls_box(ss[7],3) ^ t_use(r,c)[i]; \ - ss[0] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+ 8)] = ss[8] ^= k[v(56,(8*(i)))]; \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[8] ^= k[v(56,(8*(i))+ 1)]; \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[8] ^= k[v(56,(8*(i))+ 2)]; \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[8] ^= k[v(56,(8*(i))+ 3)]; \ - ss[8] = ls_box(ss[3],0); \ - ss[4] ^= ss[8]; ss[8] = ff(ss[8]); k[v(56,(8*(i))+12)] = ss[8] ^= k[v(56,(8*(i))+ 4)]; \ - ss[5] ^= ss[4]; k[v(56,(8*(i))+13)] = ss[8] ^= k[v(56,(8*(i))+ 5)]; \ - ss[6] ^= ss[5]; k[v(56,(8*(i))+14)] = ss[8] ^= k[v(56,(8*(i))+ 6)]; \ - ss[7] ^= ss[6]; k[v(56,(8*(i))+15)] = ss[8] ^= k[v(56,(8*(i))+ 7)]; \ -} - -#define kdl8(k,i) \ -{ ss[0] ^= ls_box(ss[7],3) ^ t_use(r,c)[i]; k[v(56,(8*(i))+ 8)] = ss[0]; \ - ss[1] ^= ss[0]; k[v(56,(8*(i))+ 9)] = ss[1]; \ - ss[2] ^= ss[1]; k[v(56,(8*(i))+10)] = ss[2]; \ - ss[3] ^= ss[2]; k[v(56,(8*(i))+11)] = ss[3]; \ -} - -AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]) -{ uint_32t ss[9]; -#if defined( d_vars ) - d_vars; -#endif - cx->ks[v(56,(0))] = ss[0] = word_in(key, 0); - cx->ks[v(56,(1))] = ss[1] = word_in(key, 1); - cx->ks[v(56,(2))] = ss[2] = word_in(key, 2); - cx->ks[v(56,(3))] = ss[3] = word_in(key, 3); - -#ifdef DEC_KS_UNROLL - ss[4] = word_in(key, 4); - cx->ks[v(56,(4))] = ff(ss[4]); - ss[5] = word_in(key, 5); - cx->ks[v(56,(5))] = ff(ss[5]); - ss[6] = word_in(key, 6); - cx->ks[v(56,(6))] = ff(ss[6]); - ss[7] = word_in(key, 7); - cx->ks[v(56,(7))] = ff(ss[7]); - kdf8(cx->ks, 0); kd8(cx->ks, 1); - kd8(cx->ks, 2); kd8(cx->ks, 3); - kd8(cx->ks, 4); kd8(cx->ks, 5); - kdl8(cx->ks, 6); -#else - cx->ks[v(56,(4))] = ss[4] = word_in(key, 4); - cx->ks[v(56,(5))] = ss[5] = word_in(key, 5); - cx->ks[v(56,(6))] = ss[6] = word_in(key, 6); - cx->ks[v(56,(7))] = ss[7] = word_in(key, 7); - { uint_32t i; - - for(i = 0; i < 6; ++i) - k8e(cx->ks, i); - k8ef(cx->ks, 6); -#if !(DEC_ROUND == NO_TABLES) - for(i = N_COLS; i < 14 * N_COLS; ++i) - cx->ks[i] = inv_mcol(cx->ks[i]); -#endif - } -#endif - cx->inf.l = 0; - cx->inf.b[0] = 14 * 16; - -#ifdef USE_VIA_ACE_IF_PRESENT - if(VIA_ACE_AVAILABLE) - cx->inf.b[1] = 0xff; -#endif - return EXIT_SUCCESS; -} - -#endif - -#if defined( AES_VAR ) - -AES_RETURN aes_decrypt_key(const unsigned char *key, int key_len, aes_decrypt_ctx cx[1]) -{ - switch(key_len) - { - case 16: case 128: return aes_decrypt_key128(key, cx); - case 24: case 192: return aes_decrypt_key192(key, cx); - case 32: case 256: return aes_decrypt_key256(key, cx); - default: return EXIT_FAILURE; - } -} - -#endif - -#endif - -#if defined(__cplusplus) -} -#endif diff --git a/libs/libks/crypt/aesopt.h b/libs/libks/crypt/aesopt.h deleted file mode 100644 index 471e0c9d38..0000000000 --- a/libs/libks/crypt/aesopt.h +++ /dev/null @@ -1,742 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the compilation options for AES (Rijndael) and code - that is common across encryption, key scheduling and table generation. - - OPERATION - - These source code files implement the AES algorithm Rijndael designed by - Joan Daemen and Vincent Rijmen. This version is designed for the standard - block size of 16 bytes and for key sizes of 128, 192 and 256 bits (16, 24 - and 32 bytes). - - This version is designed for flexibility and speed using operations on - 32-bit words rather than operations on bytes. It can be compiled with - either big or little endian internal byte order but is faster when the - native byte order for the processor is used. - - THE CIPHER INTERFACE - - The cipher interface is implemented as an array of bytes in which lower - AES bit sequence indexes map to higher numeric significance within bytes. - - uint_8t (an unsigned 8-bit type) - uint_32t (an unsigned 32-bit type) - struct aes_encrypt_ctx (structure for the cipher encryption context) - struct aes_decrypt_ctx (structure for the cipher decryption context) - AES_RETURN the function return type - - C subroutine calls: - - AES_RETURN aes_encrypt_key128(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt_key192(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt_key256(const unsigned char *key, aes_encrypt_ctx cx[1]); - AES_RETURN aes_encrypt(const unsigned char *in, unsigned char *out, - const aes_encrypt_ctx cx[1]); - - AES_RETURN aes_decrypt_key128(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt_key192(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt_key256(const unsigned char *key, aes_decrypt_ctx cx[1]); - AES_RETURN aes_decrypt(const unsigned char *in, unsigned char *out, - const aes_decrypt_ctx cx[1]); - - IMPORTANT NOTE: If you are using this C interface with dynamic tables make sure that - you call aes_init() before AES is used so that the tables are initialised. - - C++ aes class subroutines: - - Class AESencrypt for encryption - - Construtors: - AESencrypt(void) - AESencrypt(const unsigned char *key) - 128 bit key - Members: - AES_RETURN key128(const unsigned char *key) - AES_RETURN key192(const unsigned char *key) - AES_RETURN key256(const unsigned char *key) - AES_RETURN encrypt(const unsigned char *in, unsigned char *out) const - - Class AESdecrypt for encryption - Construtors: - AESdecrypt(void) - AESdecrypt(const unsigned char *key) - 128 bit key - Members: - AES_RETURN key128(const unsigned char *key) - AES_RETURN key192(const unsigned char *key) - AES_RETURN key256(const unsigned char *key) - AES_RETURN decrypt(const unsigned char *in, unsigned char *out) const -*/ - -#if !defined( _AESOPT_H ) -#define _AESOPT_H - -#if defined( __cplusplus ) -#include "aescpp.h" -#else -#include "aes.h" -#endif - -/* PLATFORM SPECIFIC INCLUDES */ - -#include "brg_endian.h" - -/* CONFIGURATION - THE USE OF DEFINES - - Later in this section there are a number of defines that control the - operation of the code. In each section, the purpose of each define is - explained so that the relevant form can be included or excluded by - setting either 1's or 0's respectively on the branches of the related - #if clauses. The following local defines should not be changed. -*/ - -#define ENCRYPTION_IN_C 1 -#define DECRYPTION_IN_C 2 -#define ENC_KEYING_IN_C 4 -#define DEC_KEYING_IN_C 8 - -#define NO_TABLES 0 -#define ONE_TABLE 1 -#define FOUR_TABLES 4 -#define NONE 0 -#define PARTIAL 1 -#define FULL 2 - -/* --- START OF USER CONFIGURED OPTIONS --- */ - -/* 1. BYTE ORDER WITHIN 32 BIT WORDS - - The fundamental data processing units in Rijndael are 8-bit bytes. The - input, output and key input are all enumerated arrays of bytes in which - bytes are numbered starting at zero and increasing to one less than the - number of bytes in the array in question. This enumeration is only used - for naming bytes and does not imply any adjacency or order relationship - from one byte to another. When these inputs and outputs are considered - as bit sequences, bits 8*n to 8*n+7 of the bit sequence are mapped to - byte[n] with bit 8n+i in the sequence mapped to bit 7-i within the byte. - In this implementation bits are numbered from 0 to 7 starting at the - numerically least significant end of each byte (bit n represents 2^n). - - However, Rijndael can be implemented more efficiently using 32-bit - words by packing bytes into words so that bytes 4*n to 4*n+3 are placed - into word[n]. While in principle these bytes can be assembled into words - in any positions, this implementation only supports the two formats in - which bytes in adjacent positions within words also have adjacent byte - numbers. This order is called big-endian if the lowest numbered bytes - in words have the highest numeric significance and little-endian if the - opposite applies. - - This code can work in either order irrespective of the order used by the - machine on which it runs. Normally the internal byte order will be set - to the order of the processor on which the code is to be run but this - define can be used to reverse this in special situations - - WARNING: Assembler code versions rely on PLATFORM_BYTE_ORDER being set. - This define will hence be redefined later (in section 4) if necessary -*/ - -#if 1 -# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER -#elif 0 -# define ALGORITHM_BYTE_ORDER IS_LITTLE_ENDIAN -#elif 0 -# define ALGORITHM_BYTE_ORDER IS_BIG_ENDIAN -#else -# error The algorithm byte order is not defined -#endif - -/* 2. VIA ACE SUPPORT */ - -#if defined( __GNUC__ ) && defined( __i386__ ) \ - || defined( _WIN32 ) && defined( _M_IX86 ) \ - && !(defined( _WIN64 ) || defined( _WIN32_WCE ) || defined( _MSC_VER ) && ( _MSC_VER <= 800 )) -# define VIA_ACE_POSSIBLE -#endif - -/* Define this option if support for the VIA ACE is required. This uses - inline assembler instructions and is only implemented for the Microsoft, - Intel and GCC compilers. If VIA ACE is known to be present, then defining - ASSUME_VIA_ACE_PRESENT will remove the ordinary encryption/decryption - code. If USE_VIA_ACE_IF_PRESENT is defined then VIA ACE will be used if - it is detected (both present and enabled) but the normal AES code will - also be present. - - When VIA ACE is to be used, all AES encryption contexts MUST be 16 byte - aligned; other input/output buffers do not need to be 16 byte aligned - but there are very large performance gains if this can be arranged. - VIA ACE also requires the decryption key schedule to be in reverse - order (which later checks below ensure). -*/ - -#if 1 && defined( VIA_ACE_POSSIBLE ) && !defined( USE_VIA_ACE_IF_PRESENT ) -# define USE_VIA_ACE_IF_PRESENT -#endif - -#if 0 && defined( VIA_ACE_POSSIBLE ) && !defined( ASSUME_VIA_ACE_PRESENT ) -# define ASSUME_VIA_ACE_PRESENT -# endif - -/* 3. ASSEMBLER SUPPORT - - This define (which can be on the command line) enables the use of the - assembler code routines for encryption, decryption and key scheduling - as follows: - - ASM_X86_V1C uses the assembler (aes_x86_v1.asm) with large tables for - encryption and decryption and but with key scheduling in C - ASM_X86_V2 uses assembler (aes_x86_v2.asm) with compressed tables for - encryption, decryption and key scheduling - ASM_X86_V2C uses assembler (aes_x86_v2.asm) with compressed tables for - encryption and decryption and but with key scheduling in C - ASM_AMD64_C uses assembler (aes_amd64.asm) with compressed tables for - encryption and decryption and but with key scheduling in C - - Change one 'if 0' below to 'if 1' to select the version or define - as a compilation option. -*/ - -#if 0 && !defined( ASM_X86_V1C ) -# define ASM_X86_V1C -#elif 0 && !defined( ASM_X86_V2 ) -# define ASM_X86_V2 -#elif 0 && !defined( ASM_X86_V2C ) -# define ASM_X86_V2C -#elif 0 && !defined( ASM_AMD64_C ) -# define ASM_AMD64_C -#endif - -#if (defined ( ASM_X86_V1C ) || defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) \ - && !defined( _M_IX86 ) || defined( ASM_AMD64_C ) && !defined( _M_X64 ) -# error Assembler code is only available for x86 and AMD64 systems -#endif - -/* 4. FAST INPUT/OUTPUT OPERATIONS. - - On some machines it is possible to improve speed by transferring the - bytes in the input and output arrays to and from the internal 32-bit - variables by addressing these arrays as if they are arrays of 32-bit - words. On some machines this will always be possible but there may - be a large performance penalty if the byte arrays are not aligned on - the normal word boundaries. On other machines this technique will - lead to memory access errors when such 32-bit word accesses are not - properly aligned. The option SAFE_IO avoids such problems but will - often be slower on those machines that support misaligned access - (especially so if care is taken to align the input and output byte - arrays on 32-bit word boundaries). If SAFE_IO is not defined it is - assumed that access to byte arrays as if they are arrays of 32-bit - words will not cause problems when such accesses are misaligned. -*/ -#if 1 && !defined( _MSC_VER ) -# define SAFE_IO -#endif - -/* 5. LOOP UNROLLING - - The code for encryption and decrytpion cycles through a number of rounds - that can be implemented either in a loop or by expanding the code into a - long sequence of instructions, the latter producing a larger program but - one that will often be much faster. The latter is called loop unrolling. - There are also potential speed advantages in expanding two iterations in - a loop with half the number of iterations, which is called partial loop - unrolling. The following options allow partial or full loop unrolling - to be set independently for encryption and decryption -*/ -#if 1 -# define ENC_UNROLL FULL -#elif 0 -# define ENC_UNROLL PARTIAL -#else -# define ENC_UNROLL NONE -#endif - -#if 1 -# define DEC_UNROLL FULL -#elif 0 -# define DEC_UNROLL PARTIAL -#else -# define DEC_UNROLL NONE -#endif - -#if 1 -# define ENC_KS_UNROLL -#endif - -#if 1 -# define DEC_KS_UNROLL -#endif - -/* 6. FAST FINITE FIELD OPERATIONS - - If this section is included, tables are used to provide faster finite - field arithmetic (this has no effect if FIXED_TABLES is defined). -*/ -#if 1 -# define FF_TABLES -#endif - -/* 7. INTERNAL STATE VARIABLE FORMAT - - The internal state of Rijndael is stored in a number of local 32-bit - word varaibles which can be defined either as an array or as individual - names variables. Include this section if you want to store these local - varaibles in arrays. Otherwise individual local variables will be used. -*/ -#if 1 -# define ARRAYS -#endif - -/* 8. FIXED OR DYNAMIC TABLES - - When this section is included the tables used by the code are compiled - statically into the binary file. Otherwise the subroutine aes_init() - must be called to compute them before the code is first used. -*/ -#if 1 && !(defined( _MSC_VER ) && ( _MSC_VER <= 800 )) -# define FIXED_TABLES -#endif - -/* 9. MASKING OR CASTING FROM LONGER VALUES TO BYTES - - In some systems it is better to mask longer values to extract bytes - rather than using a cast. This option allows this choice. -*/ -#if 0 -# define to_byte(x) ((uint_8t)(x)) -#else -# define to_byte(x) ((x) & 0xff) -#endif - -/* 10. TABLE ALIGNMENT - - On some sytsems speed will be improved by aligning the AES large lookup - tables on particular boundaries. This define should be set to a power of - two giving the desired alignment. It can be left undefined if alignment - is not needed. This option is specific to the Microsft VC++ compiler - - it seems to sometimes cause trouble for the VC++ version 6 compiler. -*/ - -#if 1 && defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) -# define TABLE_ALIGN 32 -#endif - -/* 11. REDUCE CODE AND TABLE SIZE - - This replaces some expanded macros with function calls if AES_ASM_V2 or - AES_ASM_V2C are defined -*/ - -#if 1 && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C )) -# define REDUCE_CODE_SIZE -#endif - -/* 12. TABLE OPTIONS - - This cipher proceeds by repeating in a number of cycles known as 'rounds' - which are implemented by a round function which can optionally be speeded - up using tables. The basic tables are each 256 32-bit words, with either - one or four tables being required for each round function depending on - how much speed is required. The encryption and decryption round functions - are different and the last encryption and decrytpion round functions are - different again making four different round functions in all. - - This means that: - 1. Normal encryption and decryption rounds can each use either 0, 1 - or 4 tables and table spaces of 0, 1024 or 4096 bytes each. - 2. The last encryption and decryption rounds can also use either 0, 1 - or 4 tables and table spaces of 0, 1024 or 4096 bytes each. - - Include or exclude the appropriate definitions below to set the number - of tables used by this implementation. -*/ - -#if 1 /* set tables for the normal encryption round */ -# define ENC_ROUND FOUR_TABLES -#elif 0 -# define ENC_ROUND ONE_TABLE -#else -# define ENC_ROUND NO_TABLES -#endif - -#if 1 /* set tables for the last encryption round */ -# define LAST_ENC_ROUND FOUR_TABLES -#elif 0 -# define LAST_ENC_ROUND ONE_TABLE -#else -# define LAST_ENC_ROUND NO_TABLES -#endif - -#if 1 /* set tables for the normal decryption round */ -# define DEC_ROUND FOUR_TABLES -#elif 0 -# define DEC_ROUND ONE_TABLE -#else -# define DEC_ROUND NO_TABLES -#endif - -#if 1 /* set tables for the last decryption round */ -# define LAST_DEC_ROUND FOUR_TABLES -#elif 0 -# define LAST_DEC_ROUND ONE_TABLE -#else -# define LAST_DEC_ROUND NO_TABLES -#endif - -/* The decryption key schedule can be speeded up with tables in the same - way that the round functions can. Include or exclude the following - defines to set this requirement. -*/ -#if 1 -# define KEY_SCHED FOUR_TABLES -#elif 0 -# define KEY_SCHED ONE_TABLE -#else -# define KEY_SCHED NO_TABLES -#endif - -/* ---- END OF USER CONFIGURED OPTIONS ---- */ - -/* VIA ACE support is only available for VC++ and GCC */ - -#if !defined( _MSC_VER ) && !defined( __GNUC__ ) -# if defined( ASSUME_VIA_ACE_PRESENT ) -# undef ASSUME_VIA_ACE_PRESENT -# endif -# if defined( USE_VIA_ACE_IF_PRESENT ) -# undef USE_VIA_ACE_IF_PRESENT -# endif -#endif - -#if defined( ASSUME_VIA_ACE_PRESENT ) && !defined( USE_VIA_ACE_IF_PRESENT ) -# define USE_VIA_ACE_IF_PRESENT -#endif - -#if defined( USE_VIA_ACE_IF_PRESENT ) && !defined ( AES_REV_DKS ) -# define AES_REV_DKS -#endif - -/* ********** UNDEF - we don't use VIA stuff ****************** */ -#undef USE_VIA_ACE_IF_PRESENT - -/* Assembler support requires the use of platform byte order */ - -#if ( defined( ASM_X86_V1C ) || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) ) \ - && (ALGORITHM_BYTE_ORDER != PLATFORM_BYTE_ORDER) -# undef ALGORITHM_BYTE_ORDER -# define ALGORITHM_BYTE_ORDER PLATFORM_BYTE_ORDER -#endif - -/* In this implementation the columns of the state array are each held in - 32-bit words. The state array can be held in various ways: in an array - of words, in a number of individual word variables or in a number of - processor registers. The following define maps a variable name x and - a column number c to the way the state array variable is to be held. - The first define below maps the state into an array x[c] whereas the - second form maps the state into a number of individual variables x0, - x1, etc. Another form could map individual state colums to machine - register names. -*/ - -#if defined( ARRAYS ) -# define s(x,c) x[c] -#else -# define s(x,c) x##c -#endif - -/* This implementation provides subroutines for encryption, decryption - and for setting the three key lengths (separately) for encryption - and decryption. Since not all functions are needed, masks are set - up here to determine which will be implemented in C -*/ - -#if !defined( AES_ENCRYPT ) -# define EFUNCS_IN_C 0 -#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ - || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) -# define EFUNCS_IN_C ENC_KEYING_IN_C -#elif !defined( ASM_X86_V2 ) -# define EFUNCS_IN_C ( ENCRYPTION_IN_C | ENC_KEYING_IN_C ) -#else -# define EFUNCS_IN_C 0 -#endif - -#if !defined( AES_DECRYPT ) -# define DFUNCS_IN_C 0 -#elif defined( ASSUME_VIA_ACE_PRESENT ) || defined( ASM_X86_V1C ) \ - || defined( ASM_X86_V2C ) || defined( ASM_AMD64_C ) -# define DFUNCS_IN_C DEC_KEYING_IN_C -#elif !defined( ASM_X86_V2 ) -# define DFUNCS_IN_C ( DECRYPTION_IN_C | DEC_KEYING_IN_C ) -#else -# define DFUNCS_IN_C 0 -#endif - -#define FUNCS_IN_C ( EFUNCS_IN_C | DFUNCS_IN_C ) - -/* END OF CONFIGURATION OPTIONS */ - -#define RC_LENGTH (5 * (AES_BLOCK_SIZE / 4 - 2)) - -/* Disable or report errors on some combinations of options */ - -#if ENC_ROUND == NO_TABLES && LAST_ENC_ROUND != NO_TABLES -# undef LAST_ENC_ROUND -# define LAST_ENC_ROUND NO_TABLES -#elif ENC_ROUND == ONE_TABLE && LAST_ENC_ROUND == FOUR_TABLES -# undef LAST_ENC_ROUND -# define LAST_ENC_ROUND ONE_TABLE -#endif - -#if ENC_ROUND == NO_TABLES && ENC_UNROLL != NONE -# undef ENC_UNROLL -# define ENC_UNROLL NONE -#endif - -#if DEC_ROUND == NO_TABLES && LAST_DEC_ROUND != NO_TABLES -# undef LAST_DEC_ROUND -# define LAST_DEC_ROUND NO_TABLES -#elif DEC_ROUND == ONE_TABLE && LAST_DEC_ROUND == FOUR_TABLES -# undef LAST_DEC_ROUND -# define LAST_DEC_ROUND ONE_TABLE -#endif - -#if DEC_ROUND == NO_TABLES && DEC_UNROLL != NONE -# undef DEC_UNROLL -# define DEC_UNROLL NONE -#endif - -#if defined( bswap32 ) -# define aes_sw32 bswap32 -#elif defined( bswap_32 ) -# define aes_sw32 bswap_32 -#else -# define brot(x,n) (((uint_32t)(x) << n) | ((uint_32t)(x) >> (32 - n))) -# define aes_sw32(x) ((brot((x),8) & 0x00ff00ff) | (brot((x),24) & 0xff00ff00)) -#endif - -/* upr(x,n): rotates bytes within words by n positions, moving bytes to - higher index positions with wrap around into low positions - ups(x,n): moves bytes by n positions to higher index positions in - words but without wrap around - bval(x,n): extracts a byte from a word - - WARNING: The definitions given here are intended only for use with - unsigned variables and with shift counts that are compile - time constants -*/ - -#if ( ALGORITHM_BYTE_ORDER == IS_LITTLE_ENDIAN ) -# define upr(x,n) (((uint_32t)(x) << (8 * (n))) | ((uint_32t)(x) >> (32 - 8 * (n)))) -# define ups(x,n) ((uint_32t) (x) << (8 * (n))) -# define bval(x,n) to_byte((x) >> (8 * (n))) -# define bytes2word(b0, b1, b2, b3) \ - (((uint_32t)(b3) << 24) | ((uint_32t)(b2) << 16) | ((uint_32t)(b1) << 8) | (b0)) -#endif - -#if ( ALGORITHM_BYTE_ORDER == IS_BIG_ENDIAN ) -# define upr(x,n) (((uint_32t)(x) >> (8 * (n))) | ((uint_32t)(x) << (32 - 8 * (n)))) -# define ups(x,n) ((uint_32t) (x) >> (8 * (n))) -# define bval(x,n) to_byte((x) >> (24 - 8 * (n))) -# define bytes2word(b0, b1, b2, b3) \ - (((uint_32t)(b0) << 24) | ((uint_32t)(b1) << 16) | ((uint_32t)(b2) << 8) | (b3)) -#endif - -#if defined( SAFE_IO ) -# define word_in(x,c) bytes2word(((const uint_8t*)(x)+4*c)[0], ((const uint_8t*)(x)+4*c)[1], \ - ((const uint_8t*)(x)+4*c)[2], ((const uint_8t*)(x)+4*c)[3]) -# define word_out(x,c,v) { ((uint_8t*)(x)+4*c)[0] = bval(v,0); ((uint_8t*)(x)+4*c)[1] = bval(v,1); \ - ((uint_8t*)(x)+4*c)[2] = bval(v,2); ((uint_8t*)(x)+4*c)[3] = bval(v,3); } -#elif ( ALGORITHM_BYTE_ORDER == PLATFORM_BYTE_ORDER ) -# define word_in(x,c) (*((uint_32t*)(x)+(c))) -# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = (v)) -#else -# define word_in(x,c) aes_sw32(*((uint_32t*)(x)+(c))) -# define word_out(x,c,v) (*((uint_32t*)(x)+(c)) = aes_sw32(v)) -#endif - -/* the finite field modular polynomial and elements */ - -#define WPOLY 0x011b -#define BPOLY 0x1b - -/* multiply four bytes in GF(2^8) by 'x' {02} in parallel */ - -#define gf_c1 0x80808080 -#define gf_c2 0x7f7f7f7f -#define gf_mulx(x) ((((x) & gf_c2) << 1) ^ ((((x) & gf_c1) >> 7) * BPOLY)) - -/* The following defines provide alternative definitions of gf_mulx that might - give improved performance if a fast 32-bit multiply is not available. Note - that a temporary variable u needs to be defined where gf_mulx is used. - -#define gf_mulx(x) (u = (x) & gf_c1, u |= (u >> 1), ((x) & gf_c2) << 1) ^ ((u >> 3) | (u >> 6)) -#define gf_c4 (0x01010101 * BPOLY) -#define gf_mulx(x) (u = (x) & gf_c1, ((x) & gf_c2) << 1) ^ ((u - (u >> 7)) & gf_c4) -*/ - -/* Work out which tables are needed for the different options */ - -#if defined( ASM_X86_V1C ) -# if defined( ENC_ROUND ) -# undef ENC_ROUND -# endif -# define ENC_ROUND FOUR_TABLES -# if defined( LAST_ENC_ROUND ) -# undef LAST_ENC_ROUND -# endif -# define LAST_ENC_ROUND FOUR_TABLES -# if defined( DEC_ROUND ) -# undef DEC_ROUND -# endif -# define DEC_ROUND FOUR_TABLES -# if defined( LAST_DEC_ROUND ) -# undef LAST_DEC_ROUND -# endif -# define LAST_DEC_ROUND FOUR_TABLES -# if defined( KEY_SCHED ) -# undef KEY_SCHED -# define KEY_SCHED FOUR_TABLES -# endif -#endif - -#if ( FUNCS_IN_C & ENCRYPTION_IN_C ) || defined( ASM_X86_V1C ) -# if ENC_ROUND == ONE_TABLE -# define FT1_SET -# elif ENC_ROUND == FOUR_TABLES -# define FT4_SET -# else -# define SBX_SET -# endif -# if LAST_ENC_ROUND == ONE_TABLE -# define FL1_SET -# elif LAST_ENC_ROUND == FOUR_TABLES -# define FL4_SET -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -#endif - -#if ( FUNCS_IN_C & DECRYPTION_IN_C ) || defined( ASM_X86_V1C ) -# if DEC_ROUND == ONE_TABLE -# define IT1_SET -# elif DEC_ROUND == FOUR_TABLES -# define IT4_SET -# else -# define ISB_SET -# endif -# if LAST_DEC_ROUND == ONE_TABLE -# define IL1_SET -# elif LAST_DEC_ROUND == FOUR_TABLES -# define IL4_SET -# elif !defined(ISB_SET) -# define ISB_SET -# endif -#endif - -#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) -# if ((FUNCS_IN_C & ENC_KEYING_IN_C) || (FUNCS_IN_C & DEC_KEYING_IN_C)) -# if KEY_SCHED == ONE_TABLE -# if !defined( FL1_SET ) && !defined( FL4_SET ) -# define LS1_SET -# endif -# elif KEY_SCHED == FOUR_TABLES -# if !defined( FL4_SET ) -# define LS4_SET -# endif -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -# endif -# if (FUNCS_IN_C & DEC_KEYING_IN_C) -# if KEY_SCHED == ONE_TABLE -# define IM1_SET -# elif KEY_SCHED == FOUR_TABLES -# define IM4_SET -# elif !defined( SBX_SET ) -# define SBX_SET -# endif -# endif -#endif - -/* generic definitions of Rijndael macros that use tables */ - -#define no_table(x,box,vf,rf,c) bytes2word( \ - box[bval(vf(x,0,c),rf(0,c))], \ - box[bval(vf(x,1,c),rf(1,c))], \ - box[bval(vf(x,2,c),rf(2,c))], \ - box[bval(vf(x,3,c),rf(3,c))]) - -#define one_table(x,op,tab,vf,rf,c) \ - ( tab[bval(vf(x,0,c),rf(0,c))] \ - ^ op(tab[bval(vf(x,1,c),rf(1,c))],1) \ - ^ op(tab[bval(vf(x,2,c),rf(2,c))],2) \ - ^ op(tab[bval(vf(x,3,c),rf(3,c))],3)) - -#define four_tables(x,tab,vf,rf,c) \ - ( tab[0][bval(vf(x,0,c),rf(0,c))] \ - ^ tab[1][bval(vf(x,1,c),rf(1,c))] \ - ^ tab[2][bval(vf(x,2,c),rf(2,c))] \ - ^ tab[3][bval(vf(x,3,c),rf(3,c))]) - -#define vf1(x,r,c) (x) -#define rf1(r,c) (r) -#define rf2(r,c) ((8+r-c)&3) - -/* perform forward and inverse column mix operation on four bytes in long word x in */ -/* parallel. NOTE: x must be a simple variable, NOT an expression in these macros. */ - -#if !(defined( REDUCE_CODE_SIZE ) && (defined( ASM_X86_V2 ) || defined( ASM_X86_V2C ))) - -#if defined( FM4_SET ) /* not currently used */ -# define fwd_mcol(x) four_tables(x,t_use(f,m),vf1,rf1,0) -#elif defined( FM1_SET ) /* not currently used */ -# define fwd_mcol(x) one_table(x,upr,t_use(f,m),vf1,rf1,0) -#else -# define dec_fmvars uint_32t g2 -# define fwd_mcol(x) (g2 = gf_mulx(x), g2 ^ upr((x) ^ g2, 3) ^ upr((x), 2) ^ upr((x), 1)) -#endif - -#if defined( IM4_SET ) -# define inv_mcol(x) four_tables(x,t_use(i,m),vf1,rf1,0) -#elif defined( IM1_SET ) -# define inv_mcol(x) one_table(x,upr,t_use(i,m),vf1,rf1,0) -#else -# define dec_imvars uint_32t g2, g4, g9 -# define inv_mcol(x) (g2 = gf_mulx(x), g4 = gf_mulx(g2), g9 = (x) ^ gf_mulx(g4), g4 ^= g9, \ - (x) ^ g2 ^ g4 ^ upr(g2 ^ g9, 3) ^ upr(g4, 2) ^ upr(g9, 1)) -#endif - -#if defined( FL4_SET ) -# define ls_box(x,c) four_tables(x,t_use(f,l),vf1,rf2,c) -#elif defined( LS4_SET ) -# define ls_box(x,c) four_tables(x,t_use(l,s),vf1,rf2,c) -#elif defined( FL1_SET ) -# define ls_box(x,c) one_table(x,upr,t_use(f,l),vf1,rf2,c) -#elif defined( LS1_SET ) -# define ls_box(x,c) one_table(x,upr,t_use(l,s),vf1,rf2,c) -#else -# define ls_box(x,c) no_table(x,t_use(s,box),vf1,rf2,c) -#endif - -#endif - -#if defined( ASM_X86_V1C ) && defined( AES_DECRYPT ) && !defined( ISB_SET ) -# define ISB_SET -#endif - -#endif diff --git a/libs/libks/crypt/aestab.c b/libs/libks/crypt/aestab.c deleted file mode 100644 index 4a6e43247e..0000000000 --- a/libs/libks/crypt/aestab.c +++ /dev/null @@ -1,391 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#define DO_TABLES - -#include "aes.h" -#include "aesopt.h" - -#if defined(FIXED_TABLES) - -#define sb_data(w) {\ - w(0x63), w(0x7c), w(0x77), w(0x7b), w(0xf2), w(0x6b), w(0x6f), w(0xc5),\ - w(0x30), w(0x01), w(0x67), w(0x2b), w(0xfe), w(0xd7), w(0xab), w(0x76),\ - w(0xca), w(0x82), w(0xc9), w(0x7d), w(0xfa), w(0x59), w(0x47), w(0xf0),\ - w(0xad), w(0xd4), w(0xa2), w(0xaf), w(0x9c), w(0xa4), w(0x72), w(0xc0),\ - w(0xb7), w(0xfd), w(0x93), w(0x26), w(0x36), w(0x3f), w(0xf7), w(0xcc),\ - w(0x34), w(0xa5), w(0xe5), w(0xf1), w(0x71), w(0xd8), w(0x31), w(0x15),\ - w(0x04), w(0xc7), w(0x23), w(0xc3), w(0x18), w(0x96), w(0x05), w(0x9a),\ - w(0x07), w(0x12), w(0x80), w(0xe2), w(0xeb), w(0x27), w(0xb2), w(0x75),\ - w(0x09), w(0x83), w(0x2c), w(0x1a), w(0x1b), w(0x6e), w(0x5a), w(0xa0),\ - w(0x52), w(0x3b), w(0xd6), w(0xb3), w(0x29), w(0xe3), w(0x2f), w(0x84),\ - w(0x53), w(0xd1), w(0x00), w(0xed), w(0x20), w(0xfc), w(0xb1), w(0x5b),\ - w(0x6a), w(0xcb), w(0xbe), w(0x39), w(0x4a), w(0x4c), w(0x58), w(0xcf),\ - w(0xd0), w(0xef), w(0xaa), w(0xfb), w(0x43), w(0x4d), w(0x33), w(0x85),\ - w(0x45), w(0xf9), w(0x02), w(0x7f), w(0x50), w(0x3c), w(0x9f), w(0xa8),\ - w(0x51), w(0xa3), w(0x40), w(0x8f), w(0x92), w(0x9d), w(0x38), w(0xf5),\ - w(0xbc), w(0xb6), w(0xda), w(0x21), w(0x10), w(0xff), w(0xf3), w(0xd2),\ - w(0xcd), w(0x0c), w(0x13), w(0xec), w(0x5f), w(0x97), w(0x44), w(0x17),\ - w(0xc4), w(0xa7), w(0x7e), w(0x3d), w(0x64), w(0x5d), w(0x19), w(0x73),\ - w(0x60), w(0x81), w(0x4f), w(0xdc), w(0x22), w(0x2a), w(0x90), w(0x88),\ - w(0x46), w(0xee), w(0xb8), w(0x14), w(0xde), w(0x5e), w(0x0b), w(0xdb),\ - w(0xe0), w(0x32), w(0x3a), w(0x0a), w(0x49), w(0x06), w(0x24), w(0x5c),\ - w(0xc2), w(0xd3), w(0xac), w(0x62), w(0x91), w(0x95), w(0xe4), w(0x79),\ - w(0xe7), w(0xc8), w(0x37), w(0x6d), w(0x8d), w(0xd5), w(0x4e), w(0xa9),\ - w(0x6c), w(0x56), w(0xf4), w(0xea), w(0x65), w(0x7a), w(0xae), w(0x08),\ - w(0xba), w(0x78), w(0x25), w(0x2e), w(0x1c), w(0xa6), w(0xb4), w(0xc6),\ - w(0xe8), w(0xdd), w(0x74), w(0x1f), w(0x4b), w(0xbd), w(0x8b), w(0x8a),\ - w(0x70), w(0x3e), w(0xb5), w(0x66), w(0x48), w(0x03), w(0xf6), w(0x0e),\ - w(0x61), w(0x35), w(0x57), w(0xb9), w(0x86), w(0xc1), w(0x1d), w(0x9e),\ - w(0xe1), w(0xf8), w(0x98), w(0x11), w(0x69), w(0xd9), w(0x8e), w(0x94),\ - w(0x9b), w(0x1e), w(0x87), w(0xe9), w(0xce), w(0x55), w(0x28), w(0xdf),\ - w(0x8c), w(0xa1), w(0x89), w(0x0d), w(0xbf), w(0xe6), w(0x42), w(0x68),\ - w(0x41), w(0x99), w(0x2d), w(0x0f), w(0xb0), w(0x54), w(0xbb), w(0x16) } - -#define isb_data(w) {\ - w(0x52), w(0x09), w(0x6a), w(0xd5), w(0x30), w(0x36), w(0xa5), w(0x38),\ - w(0xbf), w(0x40), w(0xa3), w(0x9e), w(0x81), w(0xf3), w(0xd7), w(0xfb),\ - w(0x7c), w(0xe3), w(0x39), w(0x82), w(0x9b), w(0x2f), w(0xff), w(0x87),\ - w(0x34), w(0x8e), w(0x43), w(0x44), w(0xc4), w(0xde), w(0xe9), w(0xcb),\ - w(0x54), w(0x7b), w(0x94), w(0x32), w(0xa6), w(0xc2), w(0x23), w(0x3d),\ - w(0xee), w(0x4c), w(0x95), w(0x0b), w(0x42), w(0xfa), w(0xc3), w(0x4e),\ - w(0x08), w(0x2e), w(0xa1), w(0x66), w(0x28), w(0xd9), w(0x24), w(0xb2),\ - w(0x76), w(0x5b), w(0xa2), w(0x49), w(0x6d), w(0x8b), w(0xd1), w(0x25),\ - w(0x72), w(0xf8), w(0xf6), w(0x64), w(0x86), w(0x68), w(0x98), w(0x16),\ - w(0xd4), w(0xa4), w(0x5c), w(0xcc), w(0x5d), w(0x65), w(0xb6), w(0x92),\ - w(0x6c), w(0x70), w(0x48), w(0x50), w(0xfd), w(0xed), w(0xb9), w(0xda),\ - w(0x5e), w(0x15), w(0x46), w(0x57), w(0xa7), w(0x8d), w(0x9d), w(0x84),\ - w(0x90), w(0xd8), w(0xab), w(0x00), w(0x8c), w(0xbc), w(0xd3), w(0x0a),\ - w(0xf7), w(0xe4), w(0x58), w(0x05), w(0xb8), w(0xb3), w(0x45), w(0x06),\ - w(0xd0), w(0x2c), w(0x1e), w(0x8f), w(0xca), w(0x3f), w(0x0f), w(0x02),\ - w(0xc1), w(0xaf), w(0xbd), w(0x03), w(0x01), w(0x13), w(0x8a), w(0x6b),\ - w(0x3a), w(0x91), w(0x11), w(0x41), w(0x4f), w(0x67), w(0xdc), w(0xea),\ - w(0x97), w(0xf2), w(0xcf), w(0xce), w(0xf0), w(0xb4), w(0xe6), w(0x73),\ - w(0x96), w(0xac), w(0x74), w(0x22), w(0xe7), w(0xad), w(0x35), w(0x85),\ - w(0xe2), w(0xf9), w(0x37), w(0xe8), w(0x1c), w(0x75), w(0xdf), w(0x6e),\ - w(0x47), w(0xf1), w(0x1a), w(0x71), w(0x1d), w(0x29), w(0xc5), w(0x89),\ - w(0x6f), w(0xb7), w(0x62), w(0x0e), w(0xaa), w(0x18), w(0xbe), w(0x1b),\ - w(0xfc), w(0x56), w(0x3e), w(0x4b), w(0xc6), w(0xd2), w(0x79), w(0x20),\ - w(0x9a), w(0xdb), w(0xc0), w(0xfe), w(0x78), w(0xcd), w(0x5a), w(0xf4),\ - w(0x1f), w(0xdd), w(0xa8), w(0x33), w(0x88), w(0x07), w(0xc7), w(0x31),\ - w(0xb1), w(0x12), w(0x10), w(0x59), w(0x27), w(0x80), w(0xec), w(0x5f),\ - w(0x60), w(0x51), w(0x7f), w(0xa9), w(0x19), w(0xb5), w(0x4a), w(0x0d),\ - w(0x2d), w(0xe5), w(0x7a), w(0x9f), w(0x93), w(0xc9), w(0x9c), w(0xef),\ - w(0xa0), w(0xe0), w(0x3b), w(0x4d), w(0xae), w(0x2a), w(0xf5), w(0xb0),\ - w(0xc8), w(0xeb), w(0xbb), w(0x3c), w(0x83), w(0x53), w(0x99), w(0x61),\ - w(0x17), w(0x2b), w(0x04), w(0x7e), w(0xba), w(0x77), w(0xd6), w(0x26),\ - w(0xe1), w(0x69), w(0x14), w(0x63), w(0x55), w(0x21), w(0x0c), w(0x7d) } - -#define mm_data(w) {\ - w(0x00), w(0x01), w(0x02), w(0x03), w(0x04), w(0x05), w(0x06), w(0x07),\ - w(0x08), w(0x09), w(0x0a), w(0x0b), w(0x0c), w(0x0d), w(0x0e), w(0x0f),\ - w(0x10), w(0x11), w(0x12), w(0x13), w(0x14), w(0x15), w(0x16), w(0x17),\ - w(0x18), w(0x19), w(0x1a), w(0x1b), w(0x1c), w(0x1d), w(0x1e), w(0x1f),\ - w(0x20), w(0x21), w(0x22), w(0x23), w(0x24), w(0x25), w(0x26), w(0x27),\ - w(0x28), w(0x29), w(0x2a), w(0x2b), w(0x2c), w(0x2d), w(0x2e), w(0x2f),\ - w(0x30), w(0x31), w(0x32), w(0x33), w(0x34), w(0x35), w(0x36), w(0x37),\ - w(0x38), w(0x39), w(0x3a), w(0x3b), w(0x3c), w(0x3d), w(0x3e), w(0x3f),\ - w(0x40), w(0x41), w(0x42), w(0x43), w(0x44), w(0x45), w(0x46), w(0x47),\ - w(0x48), w(0x49), w(0x4a), w(0x4b), w(0x4c), w(0x4d), w(0x4e), w(0x4f),\ - w(0x50), w(0x51), w(0x52), w(0x53), w(0x54), w(0x55), w(0x56), w(0x57),\ - w(0x58), w(0x59), w(0x5a), w(0x5b), w(0x5c), w(0x5d), w(0x5e), w(0x5f),\ - w(0x60), w(0x61), w(0x62), w(0x63), w(0x64), w(0x65), w(0x66), w(0x67),\ - w(0x68), w(0x69), w(0x6a), w(0x6b), w(0x6c), w(0x6d), w(0x6e), w(0x6f),\ - w(0x70), w(0x71), w(0x72), w(0x73), w(0x74), w(0x75), w(0x76), w(0x77),\ - w(0x78), w(0x79), w(0x7a), w(0x7b), w(0x7c), w(0x7d), w(0x7e), w(0x7f),\ - w(0x80), w(0x81), w(0x82), w(0x83), w(0x84), w(0x85), w(0x86), w(0x87),\ - w(0x88), w(0x89), w(0x8a), w(0x8b), w(0x8c), w(0x8d), w(0x8e), w(0x8f),\ - w(0x90), w(0x91), w(0x92), w(0x93), w(0x94), w(0x95), w(0x96), w(0x97),\ - w(0x98), w(0x99), w(0x9a), w(0x9b), w(0x9c), w(0x9d), w(0x9e), w(0x9f),\ - w(0xa0), w(0xa1), w(0xa2), w(0xa3), w(0xa4), w(0xa5), w(0xa6), w(0xa7),\ - w(0xa8), w(0xa9), w(0xaa), w(0xab), w(0xac), w(0xad), w(0xae), w(0xaf),\ - w(0xb0), w(0xb1), w(0xb2), w(0xb3), w(0xb4), w(0xb5), w(0xb6), w(0xb7),\ - w(0xb8), w(0xb9), w(0xba), w(0xbb), w(0xbc), w(0xbd), w(0xbe), w(0xbf),\ - w(0xc0), w(0xc1), w(0xc2), w(0xc3), w(0xc4), w(0xc5), w(0xc6), w(0xc7),\ - w(0xc8), w(0xc9), w(0xca), w(0xcb), w(0xcc), w(0xcd), w(0xce), w(0xcf),\ - w(0xd0), w(0xd1), w(0xd2), w(0xd3), w(0xd4), w(0xd5), w(0xd6), w(0xd7),\ - w(0xd8), w(0xd9), w(0xda), w(0xdb), w(0xdc), w(0xdd), w(0xde), w(0xdf),\ - w(0xe0), w(0xe1), w(0xe2), w(0xe3), w(0xe4), w(0xe5), w(0xe6), w(0xe7),\ - w(0xe8), w(0xe9), w(0xea), w(0xeb), w(0xec), w(0xed), w(0xee), w(0xef),\ - w(0xf0), w(0xf1), w(0xf2), w(0xf3), w(0xf4), w(0xf5), w(0xf6), w(0xf7),\ - w(0xf8), w(0xf9), w(0xfa), w(0xfb), w(0xfc), w(0xfd), w(0xfe), w(0xff) } - -#define rc_data(w) {\ - w(0x01), w(0x02), w(0x04), w(0x08), w(0x10),w(0x20), w(0x40), w(0x80),\ - w(0x1b), w(0x36) } - -#define h0(x) (x) - -#define w0(p) bytes2word(p, 0, 0, 0) -#define w1(p) bytes2word(0, p, 0, 0) -#define w2(p) bytes2word(0, 0, p, 0) -#define w3(p) bytes2word(0, 0, 0, p) - -#define u0(p) bytes2word(f2(p), p, p, f3(p)) -#define u1(p) bytes2word(f3(p), f2(p), p, p) -#define u2(p) bytes2word(p, f3(p), f2(p), p) -#define u3(p) bytes2word(p, p, f3(p), f2(p)) - -#define v0(p) bytes2word(fe(p), f9(p), fd(p), fb(p)) -#define v1(p) bytes2word(fb(p), fe(p), f9(p), fd(p)) -#define v2(p) bytes2word(fd(p), fb(p), fe(p), f9(p)) -#define v3(p) bytes2word(f9(p), fd(p), fb(p), fe(p)) - -#endif - -#if defined(FIXED_TABLES) || !defined(FF_TABLES) - -#define f2(x) ((x<<1) ^ (((x>>7) & 1) * WPOLY)) -#define f4(x) ((x<<2) ^ (((x>>6) & 1) * WPOLY) ^ (((x>>6) & 2) * WPOLY)) -#define f8(x) ((x<<3) ^ (((x>>5) & 1) * WPOLY) ^ (((x>>5) & 2) * WPOLY) \ - ^ (((x>>5) & 4) * WPOLY)) -#define f3(x) (f2(x) ^ x) -#define f9(x) (f8(x) ^ x) -#define fb(x) (f8(x) ^ f2(x) ^ x) -#define fd(x) (f8(x) ^ f4(x) ^ x) -#define fe(x) (f8(x) ^ f4(x) ^ f2(x)) - -#else - -#define f2(x) ((x) ? pow[log[x] + 0x19] : 0) -#define f3(x) ((x) ? pow[log[x] + 0x01] : 0) -#define f9(x) ((x) ? pow[log[x] + 0xc7] : 0) -#define fb(x) ((x) ? pow[log[x] + 0x68] : 0) -#define fd(x) ((x) ? pow[log[x] + 0xee] : 0) -#define fe(x) ((x) ? pow[log[x] + 0xdf] : 0) - -#endif - -#include "aestab.h" - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined(FIXED_TABLES) - -/* implemented in case of wrong call for fixed tables */ - -AES_RETURN ks_aes_init(void) -{ - return EXIT_SUCCESS; -} - -#else /* Generate the tables for the dynamic table option */ - -#if defined(FF_TABLES) - -#define gf_inv(x) ((x) ? pow[ 255 - log[x]] : 0) - -#else - -/* It will generally be sensible to use tables to compute finite - field multiplies and inverses but where memory is scarse this - code might sometimes be better. But it only has effect during - initialisation so its pretty unimportant in overall terms. -*/ - -/* return 2 ^ (n - 1) where n is the bit number of the highest bit - set in x with x in the range 1 < x < 0x00000200. This form is - used so that locals within fi can be bytes rather than words -*/ - -static uint_8t hibit(const uint_32t x) -{ uint_8t r = (uint_8t)((x >> 1) | (x >> 2)); - - r |= (r >> 2); - r |= (r >> 4); - return (r + 1) >> 1; -} - -/* return the inverse of the finite field element x */ - -static uint_8t gf_inv(const uint_8t x) -{ uint_8t p1 = x, p2 = BPOLY, n1 = hibit(x), n2 = 0x80, v1 = 1, v2 = 0; - - if(x < 2) - return x; - - for( ; ; ) - { - if(n1) - while(n2 >= n1) /* divide polynomial p2 by p1 */ - { - n2 /= n1; /* shift smaller polynomial left */ - p2 ^= (p1 * n2) & 0xff; /* and remove from larger one */ - v2 ^= v1 * n2; /* shift accumulated value and */ - n2 = hibit(p2); /* add into result */ - } - else - return v1; - - if(n2) /* repeat with values swapped */ - while(n1 >= n2) - { - n1 /= n2; - p1 ^= p2 * n1; - v1 ^= v2 * n1; - n1 = hibit(p1); - } - else - return v2; - } -} - -#endif - -/* The forward and inverse affine transformations used in the S-box */ -uint_8t fwd_affine(const uint_8t x) -{ uint_32t w = x; - w ^= (w << 1) ^ (w << 2) ^ (w << 3) ^ (w << 4); - return 0x63 ^ ((w ^ (w >> 8)) & 0xff); -} - -uint_8t inv_affine(const uint_8t x) -{ uint_32t w = x; - w = (w << 1) ^ (w << 3) ^ (w << 6); - return 0x05 ^ ((w ^ (w >> 8)) & 0xff); -} - -static int init = 0; - -AES_RETURN ks_aes_init(void) -{ uint_32t i, w; - -#if defined(FF_TABLES) - - uint_8t pow[512], log[256]; - - if(init) - return EXIT_SUCCESS; - /* log and power tables for GF(2^8) finite field with - WPOLY as modular polynomial - the simplest primitive - root is 0x03, used here to generate the tables - */ - - i = 0; w = 1; - do - { - pow[i] = (uint_8t)w; - pow[i + 255] = (uint_8t)w; - log[w] = (uint_8t)i++; - w ^= (w << 1) ^ (w & 0x80 ? WPOLY : 0); - } - while (w != 1); - -#else - if(init) - return EXIT_SUCCESS; -#endif - - for(i = 0, w = 1; i < RC_LENGTH; ++i) - { - t_set(r,c)[i] = bytes2word(w, 0, 0, 0); - w = f2(w); - } - - for(i = 0; i < 256; ++i) - { uint_8t b; - - b = fwd_affine(gf_inv((uint_8t)i)); - w = bytes2word(f2(b), b, b, f3(b)); - -#if defined( SBX_SET ) - t_set(s,box)[i] = b; -#endif - -#if defined( FT1_SET ) /* tables for a normal encryption round */ - t_set(f,n)[i] = w; -#endif -#if defined( FT4_SET ) - t_set(f,n)[0][i] = w; - t_set(f,n)[1][i] = upr(w,1); - t_set(f,n)[2][i] = upr(w,2); - t_set(f,n)[3][i] = upr(w,3); -#endif - w = bytes2word(b, 0, 0, 0); - -#if defined( FL1_SET ) /* tables for last encryption round (may also */ - t_set(f,l)[i] = w; /* be used in the key schedule) */ -#endif -#if defined( FL4_SET ) - t_set(f,l)[0][i] = w; - t_set(f,l)[1][i] = upr(w,1); - t_set(f,l)[2][i] = upr(w,2); - t_set(f,l)[3][i] = upr(w,3); -#endif - -#if defined( LS1_SET ) /* table for key schedule if t_set(f,l) above is*/ - t_set(l,s)[i] = w; /* not of the required form */ -#endif -#if defined( LS4_SET ) - t_set(l,s)[0][i] = w; - t_set(l,s)[1][i] = upr(w,1); - t_set(l,s)[2][i] = upr(w,2); - t_set(l,s)[3][i] = upr(w,3); -#endif - - b = gf_inv(inv_affine((uint_8t)i)); - w = bytes2word(fe(b), f9(b), fd(b), fb(b)); - -#if defined( IM1_SET ) /* tables for the inverse mix column operation */ - t_set(i,m)[b] = w; -#endif -#if defined( IM4_SET ) - t_set(i,m)[0][b] = w; - t_set(i,m)[1][b] = upr(w,1); - t_set(i,m)[2][b] = upr(w,2); - t_set(i,m)[3][b] = upr(w,3); -#endif - -#if defined( ISB_SET ) - t_set(i,box)[i] = b; -#endif -#if defined( IT1_SET ) /* tables for a normal decryption round */ - t_set(i,n)[i] = w; -#endif -#if defined( IT4_SET ) - t_set(i,n)[0][i] = w; - t_set(i,n)[1][i] = upr(w,1); - t_set(i,n)[2][i] = upr(w,2); - t_set(i,n)[3][i] = upr(w,3); -#endif - w = bytes2word(b, 0, 0, 0); -#if defined( IL1_SET ) /* tables for last decryption round */ - t_set(i,l)[i] = w; -#endif -#if defined( IL4_SET ) - t_set(i,l)[0][i] = w; - t_set(i,l)[1][i] = upr(w,1); - t_set(i,l)[2][i] = upr(w,2); - t_set(i,l)[3][i] = upr(w,3); -#endif - } - init = 1; - return EXIT_SUCCESS; -} - -#endif - -#if defined(__cplusplus) -} -#endif - diff --git a/libs/libks/crypt/aestab.h b/libs/libks/crypt/aestab.h deleted file mode 100644 index de685679dc..0000000000 --- a/libs/libks/crypt/aestab.h +++ /dev/null @@ -1,173 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - This file contains the code for declaring the tables needed to implement - AES. The file aesopt.h is assumed to be included before this header file. - If there are no global variables, the definitions here can be used to put - the AES tables in a structure so that a pointer can then be added to the - AES context to pass them to the AES routines that need them. If this - facility is used, the calling program has to ensure that this pointer is - managed appropriately. In particular, the value of the t_dec(in,it) item - in the table structure must be set to zero in order to ensure that the - tables are initialised. In practice the three code sequences in aeskey.c - that control the calls to aes_init() and the aes_init() routine itself will - have to be changed for a specific implementation. If global variables are - available it will generally be preferable to use them with the precomputed - FIXED_TABLES option that uses static global tables. - - The following defines can be used to control the way the tables - are defined, initialised and used in embedded environments that - require special features for these purposes - - the 't_dec' construction is used to declare fixed table arrays - the 't_set' construction is used to set fixed table values - the 't_use' construction is used to access fixed table values - - 256 byte tables: - - t_xxx(s,box) => forward S box - t_xxx(i,box) => inverse S box - - 256 32-bit word OR 4 x 256 32-bit word tables: - - t_xxx(f,n) => forward normal round - t_xxx(f,l) => forward last round - t_xxx(i,n) => inverse normal round - t_xxx(i,l) => inverse last round - t_xxx(l,s) => key schedule table - t_xxx(i,m) => key schedule table - - Other variables and tables: - - t_xxx(r,c) => the rcon table -*/ - -#if !defined( _AESTAB_H ) -#define _AESTAB_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#define t_dec(m,n) t_##m##n -#define t_set(m,n) t_##m##n -#define t_use(m,n) t_##m##n - -#if defined(FIXED_TABLES) -# if !defined( __GNUC__ ) && (defined( __MSDOS__ ) || defined( __WIN16__ )) -/* make tables far data to avoid using too much DGROUP space (PG) */ -# define CONST const far -# else -# define CONST const -# endif -#else -# define CONST -#endif - -#if defined(DO_TABLES) -# define EXTERN -#else -# define EXTERN extern -#endif - -#if defined(_MSC_VER) && defined(TABLE_ALIGN) -#define ALIGN __declspec(align(TABLE_ALIGN)) -#else -#define ALIGN -#endif - -#if defined( __WATCOMC__ ) && ( __WATCOMC__ >= 1100 ) -# define XP_DIR __cdecl -#else -# define XP_DIR -#endif - -#if defined(DO_TABLES) && defined(FIXED_TABLES) -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] = b(e) -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] = { b(e), b(f), b(g), b(h) } -EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH] = rc_data(w0); -#else -#define d_1(t,n,b,e) EXTERN ALIGN CONST XP_DIR t n[256] -#define d_4(t,n,b,e,f,g,h) EXTERN ALIGN CONST XP_DIR t n[4][256] -EXTERN ALIGN CONST uint_32t t_dec(r,c)[RC_LENGTH]; -#endif - -#if defined( SBX_SET ) - d_1(uint_8t, t_dec(s,box), sb_data, h0); -#endif -#if defined( ISB_SET ) - d_1(uint_8t, t_dec(i,box), isb_data, h0); -#endif - -#if defined( FT1_SET ) - d_1(uint_32t, t_dec(f,n), sb_data, u0); -#endif -#if defined( FT4_SET ) - d_4(uint_32t, t_dec(f,n), sb_data, u0, u1, u2, u3); -#endif - -#if defined( FL1_SET ) - d_1(uint_32t, t_dec(f,l), sb_data, w0); -#endif -#if defined( FL4_SET ) - d_4(uint_32t, t_dec(f,l), sb_data, w0, w1, w2, w3); -#endif - -#if defined( IT1_SET ) - d_1(uint_32t, t_dec(i,n), isb_data, v0); -#endif -#if defined( IT4_SET ) - d_4(uint_32t, t_dec(i,n), isb_data, v0, v1, v2, v3); -#endif - -#if defined( IL1_SET ) - d_1(uint_32t, t_dec(i,l), isb_data, w0); -#endif -#if defined( IL4_SET ) - d_4(uint_32t, t_dec(i,l), isb_data, w0, w1, w2, w3); -#endif - -#if defined( LS1_SET ) -#if defined( FL1_SET ) -#undef LS1_SET -#else - d_1(uint_32t, t_dec(l,s), sb_data, w0); -#endif -#endif - -#if defined( LS4_SET ) -#if defined( FL4_SET ) -#undef LS4_SET -#else - d_4(uint_32t, t_dec(l,s), sb_data, w0, w1, w2, w3); -#endif -#endif - -#if defined( IM1_SET ) - d_1(uint_32t, t_dec(i,m), mm_data, v0); -#endif -#if defined( IM4_SET ) - d_4(uint_32t, t_dec(i,m), mm_data, v0, v1, v2, v3); -#endif - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/libs/libks/crypt/brg_endian.h b/libs/libks/crypt/brg_endian.h deleted file mode 100644 index 0f12fbbf29..0000000000 --- a/libs/libks/crypt/brg_endian.h +++ /dev/null @@ -1,126 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 -*/ - -#ifndef _BRG_ENDIAN_H -#define _BRG_ENDIAN_H - -#define IS_BIG_ENDIAN 4321 /* byte 0 is most significant (mc68k) */ -#define IS_LITTLE_ENDIAN 1234 /* byte 0 is least significant (i386) */ - -/* Include files where endian defines and byteswap functions may reside */ -#if defined( __sun ) -# include -#elif defined( __FreeBSD__ ) || defined( __OpenBSD__ ) || defined( __NetBSD__ ) -# include -#elif defined( BSD ) && ( BSD >= 199103 ) || defined( __APPLE__ ) || \ - defined( __CYGWIN32__ ) || defined( __DJGPP__ ) || defined( __osf__ ) -# include -#elif defined( __linux__ ) || defined( __GNUC__ ) || defined( __GNU_LIBRARY__ ) -# if !defined( __MINGW32__ ) && !defined( _AIX ) -# include -# if !defined( __BEOS__ ) -# include -# endif -# endif -#endif - -/* Now attempt to set the define for platform byte order using any */ -/* of the four forms SYMBOL, _SYMBOL, __SYMBOL & __SYMBOL__, which */ -/* seem to encompass most endian symbol definitions */ - -#if defined( BIG_ENDIAN ) && defined( LITTLE_ENDIAN ) -# if defined( BYTE_ORDER ) && BYTE_ORDER == BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( BYTE_ORDER ) && BYTE_ORDER == LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( _BIG_ENDIAN ) && defined( _LITTLE_ENDIAN ) -# if defined( _BYTE_ORDER ) && _BYTE_ORDER == _BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( _BYTE_ORDER ) && _BYTE_ORDER == _LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( _BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( _LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN ) && defined( __LITTLE_ENDIAN ) -# if defined( __BYTE_ORDER ) && __BYTE_ORDER == __BIG_ENDIAN -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER ) && __BYTE_ORDER == __LITTLE_ENDIAN -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -#if defined( __BIG_ENDIAN__ ) && defined( __LITTLE_ENDIAN__ ) -# if defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __BIG_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -# elif defined( __BYTE_ORDER__ ) && __BYTE_ORDER__ == __LITTLE_ENDIAN__ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -# endif -#elif defined( __BIG_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#elif defined( __LITTLE_ENDIAN__ ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#endif - -/* if the platform byte order could not be determined, then try to */ -/* set this define using common machine defines */ -#if !defined(PLATFORM_BYTE_ORDER) - -#if defined( __alpha__ ) || defined( __alpha ) || defined( i386 ) || \ - defined( __i386__ ) || defined( _M_I86 ) || defined( _M_IX86 ) || \ - defined( __OS2__ ) || defined( sun386 ) || defined( __TURBOC__ ) || \ - defined( vax ) || defined( vms ) || defined( VMS ) || \ - defined( __VMS ) || defined( _M_X64 ) -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN - -#elif defined( AMIGA ) || defined( applec ) || defined( __AS400__ ) || \ - defined( _CRAY ) || defined( __hppa ) || defined( __hp9000 ) || \ - defined( ibm370 ) || defined( mc68000 ) || defined( m68k ) || \ - defined( __MRC__ ) || defined( __MVS__ ) || defined( __MWERKS__ ) || \ - defined( sparc ) || defined( __sparc) || defined( SYMANTEC_C ) || \ - defined( __VOS__ ) || defined( __TIGCC__ ) || defined( __TANDEM ) || \ - defined( THINK_C ) || defined( __VMCMS__ ) || defined( _AIX ) -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN - -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_LITTLE_ENDIAN -#elif 0 /* **** EDIT HERE IF NECESSARY **** */ -# define PLATFORM_BYTE_ORDER IS_BIG_ENDIAN -#else -# error Please edit lines 126 or 128 in brg_endian.h to set the platform byte order -#endif - -#endif - -#endif diff --git a/libs/libks/crypt/brg_types.h b/libs/libks/crypt/brg_types.h deleted file mode 100644 index a1d7483a4c..0000000000 --- a/libs/libks/crypt/brg_types.h +++ /dev/null @@ -1,219 +0,0 @@ -/* ---------------------------------------------------------------------------- -Copyright (c) 1998-2010, Brian Gladman, Worcester, UK. All rights reserved. - -The redistribution and use of this software (with or without changes) -is allowed without the payment of fees or royalties provided that: - - source code distributions include the above copyright notice, this - list of conditions and the following disclaimer; - - binary distributions include the above copyright notice, this list - of conditions and the following disclaimer in their documentation. - -This software is provided 'as is' with no explicit or implied warranties -in respect of its operation, including, but not limited to, correctness -and fitness for purpose. ---------------------------------------------------------------------------- -Issue Date: 20/12/2007 - - The unsigned integer types defined here are of the form uint_t where - is the length of the type; for example, the unsigned 32-bit type is - 'uint_32t'. These are NOT the same as the 'C99 integer types' that are - defined in the inttypes.h and stdint.h headers since attempts to use these - types have shown that support for them is still highly variable. However, - since the latter are of the form uint_t, a regular expression search - and replace (in VC++ search on 'uint_{:z}t' and replace with 'uint\1_t') - can be used to convert the types used here to the C99 standard types. -*/ - -#ifndef _BRG_TYPES_H -#define _BRG_TYPES_H - -#if defined(__cplusplus) -extern "C" { -#endif - -#include - -#if defined( _MSC_VER ) && ( _MSC_VER >= 1300 ) -# include -# define ptrint_t intptr_t -#elif defined( __ECOS__ ) -# define intptr_t unsigned int -# define ptrint_t intptr_t -#elif defined( __GNUC__ ) && ( __GNUC__ >= 3 ) -# include -# define ptrint_t intptr_t -#else -# define ptrint_t int -#endif - -#ifndef BRG_UI8 -# define BRG_UI8 -# if UCHAR_MAX == 255u - typedef unsigned char uint_8t; -# else -# error Please define uint_8t as an 8-bit unsigned integer type in brg_types.h -# endif -#endif - -#ifndef BRG_UI16 -# define BRG_UI16 -# if USHRT_MAX == 65535u - typedef unsigned short uint_16t; -# else -# error Please define uint_16t as a 16-bit unsigned short type in brg_types.h -# endif -#endif - -#ifndef BRG_UI32 -# define BRG_UI32 -# if UINT_MAX == 4294967295u -# define li_32(h) 0x##h##u - typedef unsigned int uint_32t; -# elif ULONG_MAX == 4294967295u -# define li_32(h) 0x##h##ul - typedef unsigned long uint_32t; -# elif defined( _CRAY ) -# error This code needs 32-bit data types, which Cray machines do not provide -# else -# error Please define uint_32t as a 32-bit unsigned integer type in brg_types.h -# endif -#endif - -#ifndef BRG_UI64 -# if defined( __BORLANDC__ ) && !defined( __MSDOS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 - typedef unsigned __int64 uint_64t; -# elif defined( _MSC_VER ) && ( _MSC_VER < 1300 ) /* 1300 == VC++ 7.0 */ -# define BRG_UI64 -# define li_64(h) 0x##h##ui64 - typedef unsigned __int64 uint_64t; -# elif defined( __sun ) && defined( ULONG_MAX ) && ULONG_MAX == 0xfffffffful -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned long long uint_64t; -# elif defined( __MVS__ ) -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned int long long uint_64t; -# elif defined( UINT_MAX ) && UINT_MAX > 4294967295u -# if UINT_MAX == 18446744073709551615u -# define BRG_UI64 -# define li_64(h) 0x##h##u - typedef unsigned int uint_64t; -# endif -# elif defined( ULONG_MAX ) && ULONG_MAX > 4294967295u -# if ULONG_MAX == 18446744073709551615ul -# define BRG_UI64 -# define li_64(h) 0x##h##ul - typedef unsigned long uint_64t; -# endif -# elif defined( ULLONG_MAX ) && ULLONG_MAX > 4294967295u -# if ULLONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned long long uint_64t; -# endif -# elif defined( ULONG_LONG_MAX ) && ULONG_LONG_MAX > 4294967295u -# if ULONG_LONG_MAX == 18446744073709551615ull -# define BRG_UI64 -# define li_64(h) 0x##h##ull - typedef unsigned long long uint_64t; -# endif -# endif -#endif - -#if !defined( BRG_UI64 ) -# if defined( NEED_UINT_64T ) -# error Please define uint_64t as an unsigned 64 bit type in brg_types.h -# endif -#endif - -#ifndef RETURN_VALUES -# define RETURN_VALUES -# if defined( DLL_EXPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllexport ) void __stdcall -# define INT_RETURN __declspec( dllexport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllexport__ ) void -# define INT_RETURN __declspec( __dllexport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( DLL_IMPORT ) -# if defined( _MSC_VER ) || defined ( __INTEL_COMPILER ) -# define VOID_RETURN __declspec( dllimport ) void __stdcall -# define INT_RETURN __declspec( dllimport ) int __stdcall -# elif defined( __GNUC__ ) -# define VOID_RETURN __declspec( __dllimport__ ) void -# define INT_RETURN __declspec( __dllimport__ ) int -# else -# error Use of the DLL is only available on the Microsoft, Intel and GCC compilers -# endif -# elif defined( __WATCOMC__ ) -# define VOID_RETURN void __cdecl -# define INT_RETURN int __cdecl -# else -# define VOID_RETURN void -# define INT_RETURN int -# endif -#endif - -/* These defines are used to detect and set the memory alignment of pointers. - Note that offsets are in bytes. - - ALIGN_OFFSET(x,n) return the positive or zero offset of - the memory addressed by the pointer 'x' - from an address that is aligned on an - 'n' byte boundary ('n' is a power of 2) - - ALIGN_FLOOR(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not higher than the memory address - pointed to by 'x' ('n' is a power of 2) - - ALIGN_CEIL(x,n) return a pointer that points to memory - that is aligned on an 'n' byte boundary - and is not lower than the memory address - pointed to by 'x' ('n' is a power of 2) -*/ - -#define ALIGN_OFFSET(x,n) (((ptrint_t)(x)) & ((n) - 1)) -#define ALIGN_FLOOR(x,n) ((uint_8t*)(x) - ( ((ptrint_t)(x)) & ((n) - 1))) -#define ALIGN_CEIL(x,n) ((uint_8t*)(x) + (-((ptrint_t)(x)) & ((n) - 1))) - -/* These defines are used to declare buffers in a way that allows - faster operations on longer variables to be used. In all these - defines 'size' must be a power of 2 and >= 8. NOTE that the - buffer size is in bytes but the type length is in bits - - UNIT_TYPEDEF(x,size) declares a variable 'x' of length - 'size' bits - - BUFR_TYPEDEF(x,size,bsize) declares a buffer 'x' of length 'bsize' - bytes defined as an array of variables - each of 'size' bits (bsize must be a - multiple of size / 8) - - UNIT_CAST(x,size) casts a variable to a type of - length 'size' bits - - UPTR_CAST(x,size) casts a pointer to a pointer to a - varaiable of length 'size' bits -*/ - -#define UI_TYPE(size) uint_##size##t -#define UNIT_TYPEDEF(x,size) typedef UI_TYPE(size) x -#define BUFR_TYPEDEF(x,size,bsize) typedef UI_TYPE(size) x[bsize / (size >> 3)] -#define UNIT_CAST(x,size) ((UI_TYPE(size) )(x)) -#define UPTR_CAST(x,size) ((UI_TYPE(size)*)(x)) - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/libs/libks/crypt/sha2.c b/libs/libks/crypt/sha2.c deleted file mode 100644 index 5b565d0e01..0000000000 --- a/libs/libks/crypt/sha2.c +++ /dev/null @@ -1,773 +0,0 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 01/08/2005 - - This is a byte oriented version of SHA2 that operates on arrays of bytes - stored in memory. This code implements sha256, sha384 and sha512 but the - latter two functions rely on efficient 64-bit integer operations that - may not be very efficient on 32-bit machines - - The sha256 functions use a type 'sha256_ctx' to hold details of the - current hash state and uses the following three calls: - - void sha256_begin(sha256_ctx ctx[1]) - void sha256_hash(const unsigned char data[], - unsigned long len, sha256_ctx ctx[1]) - void sha_end1(unsigned char hval[], sha256_ctx ctx[1]) - - The first subroutine initialises a hash computation by setting up the - context in the sha256_ctx context. The second subroutine hashes 8-bit - bytes from array data[] into the hash state withinh sha256_ctx context, - the number of bytes to be hashed being given by the the unsigned long - integer len. The third subroutine completes the hash calculation and - places the resulting digest value in the array of 8-bit bytes hval[]. - - The sha384 and sha512 functions are similar and use the interfaces: - - void sha384_begin(sha384_ctx ctx[1]); - void sha384_hash(const unsigned char data[], - unsigned long len, sha384_ctx ctx[1]); - void sha384_end(unsigned char hval[], sha384_ctx ctx[1]); - - void sha512_begin(sha512_ctx ctx[1]); - void sha512_hash(const unsigned char data[], - unsigned long len, sha512_ctx ctx[1]); - void sha512_end(unsigned char hval[], sha512_ctx ctx[1]); - - In addition there is a function sha2 that can be used to call all these - functions using a call with a hash length parameter as follows: - - int sha2_begin(unsigned long len, sha2_ctx ctx[1]); - void sha2_hash(const unsigned char data[], - unsigned long len, sha2_ctx ctx[1]); - void sha2_end(unsigned char hval[], sha2_ctx ctx[1]); - - My thanks to Erik Andersen for testing this code - on big-endian systems and for his assistance with corrections -*/ - -#if 0 -#define UNROLL_SHA2 /* for SHA2 loop unroll */ -#endif - -#include /* for memcpy() etc. */ - -#include "sha2.h" - -#include - -#if defined(__cplusplus) -extern "C" -{ -#endif - -#if defined( _MSC_VER ) && ( _MSC_VER > 800 ) -#pragma intrinsic(memcpy) -#endif - -#if 0 && defined(_MSC_VER) -#define rotl32 _lrotl -#define rotr32 _lrotr -#else -#define rotl32(x,n) (((x) << n) | ((x) >> (32 - n))) -#define rotr32(x,n) (((x) >> n) | ((x) << (32 - n))) -#endif - -#if !defined(bswap_32) -#define bswap_32(x) ((rotr32((x), 24) & 0x00ff00ff) | (rotr32((x), 8) & 0xff00ff00)) -#endif - -#if (PLATFORM_BYTE_ORDER == IS_LITTLE_ENDIAN) -#define SWAP_BYTES -#else -#undef SWAP_BYTES -#endif - -#if 0 - -#define ch(x,y,z) (((x) & (y)) ^ (~(x) & (z))) -#define maj(x,y,z) (((x) & (y)) ^ ((x) & (z)) ^ ((y) & (z))) - -#else /* Thanks to Rich Schroeppel and Colin Plumb for the following */ - -#define ch(x,y,z) ((z) ^ ((x) & ((y) ^ (z)))) -#define maj(x,y,z) (((x) & (y)) | ((z) & ((x) ^ (y)))) - -#endif - -/* round transforms for SHA256 and SHA512 compression functions */ - -#define vf(n,i) v[(n - i) & 7] - -#define hf(i) (p[i & 15] += \ - g_1(p[(i + 14) & 15]) + p[(i + 9) & 15] + g_0(p[(i + 1) & 15])) - -#define v_cycle(i,j) \ - vf(7,i) += (j ? hf(i) : p[i]) + k_0[i+j] \ - + s_1(vf(4,i)) + ch(vf(4,i),vf(5,i),vf(6,i)); \ - vf(3,i) += vf(7,i); \ - vf(7,i) += s_0(vf(0,i))+ maj(vf(0,i),vf(1,i),vf(2,i)) - -#if defined(SHA_224) || defined(SHA_256) - -#define SHA256_MASK (SHA256_BLOCK_SIZE - 1) - -#if defined(SWAP_BYTES) -#define bsw_32(p,n) \ - { int _i = (n); while(_i--) ((uint_32t*)p)[_i] = bswap_32(((uint_32t*)p)[_i]); } -#else -#define bsw_32(p,n) -#endif - -#define s_0(x) (rotr32((x), 2) ^ rotr32((x), 13) ^ rotr32((x), 22)) -#define s_1(x) (rotr32((x), 6) ^ rotr32((x), 11) ^ rotr32((x), 25)) -#define g_0(x) (rotr32((x), 7) ^ rotr32((x), 18) ^ ((x) >> 3)) -#define g_1(x) (rotr32((x), 17) ^ rotr32((x), 19) ^ ((x) >> 10)) -#define k_0 k256 - -/* rotated SHA256 round definition. Rather than swapping variables as in */ -/* FIPS-180, different variables are 'rotated' on each round, returning */ -/* to their starting positions every eight rounds */ - -#define q(n) v##n - -#define one_cycle(a,b,c,d,e,f,g,h,k,w) \ - q(h) += s_1(q(e)) + ch(q(e), q(f), q(g)) + k + w; \ - q(d) += q(h); q(h) += s_0(q(a)) + maj(q(a), q(b), q(c)) - -/* SHA256 mixing data */ - -const uint_32t k256[64] = -{ 0x428a2f98ul, 0x71374491ul, 0xb5c0fbcful, 0xe9b5dba5ul, - 0x3956c25bul, 0x59f111f1ul, 0x923f82a4ul, 0xab1c5ed5ul, - 0xd807aa98ul, 0x12835b01ul, 0x243185beul, 0x550c7dc3ul, - 0x72be5d74ul, 0x80deb1feul, 0x9bdc06a7ul, 0xc19bf174ul, - 0xe49b69c1ul, 0xefbe4786ul, 0x0fc19dc6ul, 0x240ca1ccul, - 0x2de92c6ful, 0x4a7484aaul, 0x5cb0a9dcul, 0x76f988daul, - 0x983e5152ul, 0xa831c66dul, 0xb00327c8ul, 0xbf597fc7ul, - 0xc6e00bf3ul, 0xd5a79147ul, 0x06ca6351ul, 0x14292967ul, - 0x27b70a85ul, 0x2e1b2138ul, 0x4d2c6dfcul, 0x53380d13ul, - 0x650a7354ul, 0x766a0abbul, 0x81c2c92eul, 0x92722c85ul, - 0xa2bfe8a1ul, 0xa81a664bul, 0xc24b8b70ul, 0xc76c51a3ul, - 0xd192e819ul, 0xd6990624ul, 0xf40e3585ul, 0x106aa070ul, - 0x19a4c116ul, 0x1e376c08ul, 0x2748774cul, 0x34b0bcb5ul, - 0x391c0cb3ul, 0x4ed8aa4aul, 0x5b9cca4ful, 0x682e6ff3ul, - 0x748f82eeul, 0x78a5636ful, 0x84c87814ul, 0x8cc70208ul, - 0x90befffaul, 0xa4506cebul, 0xbef9a3f7ul, 0xc67178f2ul, -}; - -/* Compile 64 bytes of hash data into SHA256 digest value */ -/* NOTE: this routine assumes that the byte order in the */ -/* ctx->wbuf[] at this point is such that low address bytes */ -/* in the ORIGINAL byte stream will go into the high end of */ -/* words on BOTH big and little endian systems */ - -VOID_RETURN sha256_compile(sha256_ctx ctx[1]) -{ -#if !defined(UNROLL_SHA2) - - uint_32t j, *p = ctx->wbuf, v[8]; - - memcpy(v, ctx->hash, 8 * sizeof(uint_32t)); - - for(j = 0; j < 64; j += 16) - { - v_cycle( 0, j); v_cycle( 1, j); - v_cycle( 2, j); v_cycle( 3, j); - v_cycle( 4, j); v_cycle( 5, j); - v_cycle( 6, j); v_cycle( 7, j); - v_cycle( 8, j); v_cycle( 9, j); - v_cycle(10, j); v_cycle(11, j); - v_cycle(12, j); v_cycle(13, j); - v_cycle(14, j); v_cycle(15, j); - } - - ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; - ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; - ctx->hash[4] += v[4]; ctx->hash[5] += v[5]; - ctx->hash[6] += v[6]; ctx->hash[7] += v[7]; - -#else - - uint_32t *p = ctx->wbuf,v0,v1,v2,v3,v4,v5,v6,v7; - - v0 = ctx->hash[0]; v1 = ctx->hash[1]; - v2 = ctx->hash[2]; v3 = ctx->hash[3]; - v4 = ctx->hash[4]; v5 = ctx->hash[5]; - v6 = ctx->hash[6]; v7 = ctx->hash[7]; - - one_cycle(0,1,2,3,4,5,6,7,k256[ 0],p[ 0]); - one_cycle(7,0,1,2,3,4,5,6,k256[ 1],p[ 1]); - one_cycle(6,7,0,1,2,3,4,5,k256[ 2],p[ 2]); - one_cycle(5,6,7,0,1,2,3,4,k256[ 3],p[ 3]); - one_cycle(4,5,6,7,0,1,2,3,k256[ 4],p[ 4]); - one_cycle(3,4,5,6,7,0,1,2,k256[ 5],p[ 5]); - one_cycle(2,3,4,5,6,7,0,1,k256[ 6],p[ 6]); - one_cycle(1,2,3,4,5,6,7,0,k256[ 7],p[ 7]); - one_cycle(0,1,2,3,4,5,6,7,k256[ 8],p[ 8]); - one_cycle(7,0,1,2,3,4,5,6,k256[ 9],p[ 9]); - one_cycle(6,7,0,1,2,3,4,5,k256[10],p[10]); - one_cycle(5,6,7,0,1,2,3,4,k256[11],p[11]); - one_cycle(4,5,6,7,0,1,2,3,k256[12],p[12]); - one_cycle(3,4,5,6,7,0,1,2,k256[13],p[13]); - one_cycle(2,3,4,5,6,7,0,1,k256[14],p[14]); - one_cycle(1,2,3,4,5,6,7,0,k256[15],p[15]); - - one_cycle(0,1,2,3,4,5,6,7,k256[16],hf( 0)); - one_cycle(7,0,1,2,3,4,5,6,k256[17],hf( 1)); - one_cycle(6,7,0,1,2,3,4,5,k256[18],hf( 2)); - one_cycle(5,6,7,0,1,2,3,4,k256[19],hf( 3)); - one_cycle(4,5,6,7,0,1,2,3,k256[20],hf( 4)); - one_cycle(3,4,5,6,7,0,1,2,k256[21],hf( 5)); - one_cycle(2,3,4,5,6,7,0,1,k256[22],hf( 6)); - one_cycle(1,2,3,4,5,6,7,0,k256[23],hf( 7)); - one_cycle(0,1,2,3,4,5,6,7,k256[24],hf( 8)); - one_cycle(7,0,1,2,3,4,5,6,k256[25],hf( 9)); - one_cycle(6,7,0,1,2,3,4,5,k256[26],hf(10)); - one_cycle(5,6,7,0,1,2,3,4,k256[27],hf(11)); - one_cycle(4,5,6,7,0,1,2,3,k256[28],hf(12)); - one_cycle(3,4,5,6,7,0,1,2,k256[29],hf(13)); - one_cycle(2,3,4,5,6,7,0,1,k256[30],hf(14)); - one_cycle(1,2,3,4,5,6,7,0,k256[31],hf(15)); - - one_cycle(0,1,2,3,4,5,6,7,k256[32],hf( 0)); - one_cycle(7,0,1,2,3,4,5,6,k256[33],hf( 1)); - one_cycle(6,7,0,1,2,3,4,5,k256[34],hf( 2)); - one_cycle(5,6,7,0,1,2,3,4,k256[35],hf( 3)); - one_cycle(4,5,6,7,0,1,2,3,k256[36],hf( 4)); - one_cycle(3,4,5,6,7,0,1,2,k256[37],hf( 5)); - one_cycle(2,3,4,5,6,7,0,1,k256[38],hf( 6)); - one_cycle(1,2,3,4,5,6,7,0,k256[39],hf( 7)); - one_cycle(0,1,2,3,4,5,6,7,k256[40],hf( 8)); - one_cycle(7,0,1,2,3,4,5,6,k256[41],hf( 9)); - one_cycle(6,7,0,1,2,3,4,5,k256[42],hf(10)); - one_cycle(5,6,7,0,1,2,3,4,k256[43],hf(11)); - one_cycle(4,5,6,7,0,1,2,3,k256[44],hf(12)); - one_cycle(3,4,5,6,7,0,1,2,k256[45],hf(13)); - one_cycle(2,3,4,5,6,7,0,1,k256[46],hf(14)); - one_cycle(1,2,3,4,5,6,7,0,k256[47],hf(15)); - - one_cycle(0,1,2,3,4,5,6,7,k256[48],hf( 0)); - one_cycle(7,0,1,2,3,4,5,6,k256[49],hf( 1)); - one_cycle(6,7,0,1,2,3,4,5,k256[50],hf( 2)); - one_cycle(5,6,7,0,1,2,3,4,k256[51],hf( 3)); - one_cycle(4,5,6,7,0,1,2,3,k256[52],hf( 4)); - one_cycle(3,4,5,6,7,0,1,2,k256[53],hf( 5)); - one_cycle(2,3,4,5,6,7,0,1,k256[54],hf( 6)); - one_cycle(1,2,3,4,5,6,7,0,k256[55],hf( 7)); - one_cycle(0,1,2,3,4,5,6,7,k256[56],hf( 8)); - one_cycle(7,0,1,2,3,4,5,6,k256[57],hf( 9)); - one_cycle(6,7,0,1,2,3,4,5,k256[58],hf(10)); - one_cycle(5,6,7,0,1,2,3,4,k256[59],hf(11)); - one_cycle(4,5,6,7,0,1,2,3,k256[60],hf(12)); - one_cycle(3,4,5,6,7,0,1,2,k256[61],hf(13)); - one_cycle(2,3,4,5,6,7,0,1,k256[62],hf(14)); - one_cycle(1,2,3,4,5,6,7,0,k256[63],hf(15)); - - ctx->hash[0] += v0; ctx->hash[1] += v1; - ctx->hash[2] += v2; ctx->hash[3] += v3; - ctx->hash[4] += v4; ctx->hash[5] += v5; - ctx->hash[6] += v6; ctx->hash[7] += v7; -#endif -} - -/* SHA256 hash data in an array of bytes into hash buffer */ -/* and call the hash_compile function as required. */ - -VOID_RETURN sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1]) -{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA256_MASK), - space = SHA256_BLOCK_SIZE - pos; - const unsigned char *sp = data; - - if((ctx->count[0] += len) < len) - ++(ctx->count[1]); - - while(len >= space) /* tranfer whole blocks while possible */ - { - memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); - sp += space; len -= space; space = SHA256_BLOCK_SIZE; pos = 0; - bsw_32(ctx->wbuf, SHA256_BLOCK_SIZE >> 2) - sha256_compile(ctx); - } - - memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); -} - -/* SHA256 Final padding and digest calculation */ - -static void sha_end1(unsigned char hval[], sha256_ctx ctx[1], const unsigned int hlen) -{ uint_32t i = (uint_32t)(ctx->count[0] & SHA256_MASK); - - /* put bytes in the buffer in an order in which references to */ - /* 32-bit words will put bytes with lower addresses into the */ - /* top of 32 bit words on BOTH big and little endian machines */ - bsw_32(ctx->wbuf, (i + 3) >> 2) - - /* we now need to mask valid bytes and add the padding which is */ - /* a single 1 bit and as many zero bits as necessary. Note that */ - /* we can always add the first padding byte here because the */ - /* buffer always has at least one empty slot */ - ctx->wbuf[i >> 2] &= 0xffffff80 << 8 * (~i & 3); - ctx->wbuf[i >> 2] |= 0x00000080 << 8 * (~i & 3); - - /* we need 9 or more empty positions, one for the padding byte */ - /* (above) and eight for the length count. If there is not */ - /* enough space pad and empty the buffer */ - if(i > SHA256_BLOCK_SIZE - 9) - { - if(i < 60) ctx->wbuf[15] = 0; - sha256_compile(ctx); - i = 0; - } - else /* compute a word index for the empty buffer positions */ - i = (i >> 2) + 1; - - while(i < 14) /* and zero pad all but last two positions */ - ctx->wbuf[i++] = 0; - - /* the following 32-bit length fields are assembled in the */ - /* wrong byte order on little endian machines but this is */ - /* corrected later since they are only ever used as 32-bit */ - /* word values. */ - ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 29); - ctx->wbuf[15] = ctx->count[0] << 3; - sha256_compile(ctx); - - /* extract the hash value as bytes in case the hash buffer is */ - /* mislaigned for 32-bit words */ - for(i = 0; i < hlen; ++i) - hval[i] = (unsigned char)(ctx->hash[i >> 2] >> (8 * (~i & 3))); -} - -#endif - -#if defined(SHA_224) - -const uint_32t i224[8] = -{ - 0xc1059ed8ul, 0x367cd507ul, 0x3070dd17ul, 0xf70e5939ul, - 0xffc00b31ul, 0x68581511ul, 0x64f98fa7ul, 0xbefa4fa4ul -}; - -VOID_RETURN sha224_begin(sha224_ctx ctx[1]) -{ - ctx->count[0] = ctx->count[1] = 0; - memcpy(ctx->hash, i224, 8 * sizeof(uint_32t)); -} - -VOID_RETURN sha224_end(unsigned char hval[], sha224_ctx ctx[1]) -{ - sha_end1(hval, ctx, SHA224_DIGEST_SIZE); -} - -VOID_RETURN sha224_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len) -{ sha224_ctx cx[1]; - - sha224_begin(cx); - sha224_hash(data, len, cx); - sha_end1(hval, cx, SHA224_DIGEST_SIZE); -} - -#endif - -#if defined(SHA_256) - -const uint_32t i256[8] = -{ - 0x6a09e667ul, 0xbb67ae85ul, 0x3c6ef372ul, 0xa54ff53aul, - 0x510e527ful, 0x9b05688cul, 0x1f83d9abul, 0x5be0cd19ul -}; - -VOID_RETURN sha256_begin(sha256_ctx ctx[1]) -{ - ctx->count[0] = ctx->count[1] = 0; - memcpy(ctx->hash, i256, 8 * sizeof(uint_32t)); -} - -VOID_RETURN sha256_end(unsigned char hval[], sha256_ctx ctx[1]) -{ - sha_end1(hval, ctx, SHA256_DIGEST_SIZE); -} - -VOID_RETURN sha256_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len) -{ sha256_ctx cx[1]; - - sha256_begin(cx); - sha256_hash(data, len, cx); - sha_end1(hval, cx, SHA256_DIGEST_SIZE); -} - -#endif - -#if defined(SHA_384) || defined(SHA_512) - -#define SHA512_MASK (SHA512_BLOCK_SIZE - 1) - -#define rotr64(x,n) (((x) >> n) | ((x) << (64 - n))) - -#if !defined(bswap_64) -#define bswap_64(x) (((uint_64t)(bswap_32((uint_32t)(x)))) << 32 | bswap_32((uint_32t)((x) >> 32))) -#endif - -#if defined(SWAP_BYTES) -#define bsw_64(p,n) \ - { int _i = (n); while(_i--) ((uint_64t*)p)[_i] = bswap_64(((uint_64t*)p)[_i]); } -#else -#define bsw_64(p,n) -#endif - -/* SHA512 mixing function definitions */ - -#ifdef s_0 -# undef s_0 -# undef s_1 -# undef g_0 -# undef g_1 -# undef k_0 -#endif - -#define s_0(x) (rotr64((x), 28) ^ rotr64((x), 34) ^ rotr64((x), 39)) -#define s_1(x) (rotr64((x), 14) ^ rotr64((x), 18) ^ rotr64((x), 41)) -#define g_0(x) (rotr64((x), 1) ^ rotr64((x), 8) ^ ((x) >> 7)) -#define g_1(x) (rotr64((x), 19) ^ rotr64((x), 61) ^ ((x) >> 6)) -#define k_0 k512 - -/* SHA384/SHA512 mixing data */ - -const uint_64t k512[80] = -{ - li_64(428a2f98d728ae22), li_64(7137449123ef65cd), - li_64(b5c0fbcfec4d3b2f), li_64(e9b5dba58189dbbc), - li_64(3956c25bf348b538), li_64(59f111f1b605d019), - li_64(923f82a4af194f9b), li_64(ab1c5ed5da6d8118), - li_64(d807aa98a3030242), li_64(12835b0145706fbe), - li_64(243185be4ee4b28c), li_64(550c7dc3d5ffb4e2), - li_64(72be5d74f27b896f), li_64(80deb1fe3b1696b1), - li_64(9bdc06a725c71235), li_64(c19bf174cf692694), - li_64(e49b69c19ef14ad2), li_64(efbe4786384f25e3), - li_64(0fc19dc68b8cd5b5), li_64(240ca1cc77ac9c65), - li_64(2de92c6f592b0275), li_64(4a7484aa6ea6e483), - li_64(5cb0a9dcbd41fbd4), li_64(76f988da831153b5), - li_64(983e5152ee66dfab), li_64(a831c66d2db43210), - li_64(b00327c898fb213f), li_64(bf597fc7beef0ee4), - li_64(c6e00bf33da88fc2), li_64(d5a79147930aa725), - li_64(06ca6351e003826f), li_64(142929670a0e6e70), - li_64(27b70a8546d22ffc), li_64(2e1b21385c26c926), - li_64(4d2c6dfc5ac42aed), li_64(53380d139d95b3df), - li_64(650a73548baf63de), li_64(766a0abb3c77b2a8), - li_64(81c2c92e47edaee6), li_64(92722c851482353b), - li_64(a2bfe8a14cf10364), li_64(a81a664bbc423001), - li_64(c24b8b70d0f89791), li_64(c76c51a30654be30), - li_64(d192e819d6ef5218), li_64(d69906245565a910), - li_64(f40e35855771202a), li_64(106aa07032bbd1b8), - li_64(19a4c116b8d2d0c8), li_64(1e376c085141ab53), - li_64(2748774cdf8eeb99), li_64(34b0bcb5e19b48a8), - li_64(391c0cb3c5c95a63), li_64(4ed8aa4ae3418acb), - li_64(5b9cca4f7763e373), li_64(682e6ff3d6b2b8a3), - li_64(748f82ee5defb2fc), li_64(78a5636f43172f60), - li_64(84c87814a1f0ab72), li_64(8cc702081a6439ec), - li_64(90befffa23631e28), li_64(a4506cebde82bde9), - li_64(bef9a3f7b2c67915), li_64(c67178f2e372532b), - li_64(ca273eceea26619c), li_64(d186b8c721c0c207), - li_64(eada7dd6cde0eb1e), li_64(f57d4f7fee6ed178), - li_64(06f067aa72176fba), li_64(0a637dc5a2c898a6), - li_64(113f9804bef90dae), li_64(1b710b35131c471b), - li_64(28db77f523047d84), li_64(32caab7b40c72493), - li_64(3c9ebe0a15c9bebc), li_64(431d67c49c100d4c), - li_64(4cc5d4becb3e42b6), li_64(597f299cfc657e2a), - li_64(5fcb6fab3ad6faec), li_64(6c44198c4a475817) -}; - -/* Compile 128 bytes of hash data into SHA384/512 digest */ -/* NOTE: this routine assumes that the byte order in the */ -/* ctx->wbuf[] at this point is such that low address bytes */ -/* in the ORIGINAL byte stream will go into the high end of */ -/* words on BOTH big and little endian systems */ - -VOID_RETURN sha512_compile(sha512_ctx ctx[1]) -{ uint_64t v[8], *p = ctx->wbuf; - uint_32t j; - - memcpy(v, ctx->hash, 8 * sizeof(uint_64t)); - - for(j = 0; j < 80; j += 16) - { - v_cycle( 0, j); v_cycle( 1, j); - v_cycle( 2, j); v_cycle( 3, j); - v_cycle( 4, j); v_cycle( 5, j); - v_cycle( 6, j); v_cycle( 7, j); - v_cycle( 8, j); v_cycle( 9, j); - v_cycle(10, j); v_cycle(11, j); - v_cycle(12, j); v_cycle(13, j); - v_cycle(14, j); v_cycle(15, j); - } - - ctx->hash[0] += v[0]; ctx->hash[1] += v[1]; - ctx->hash[2] += v[2]; ctx->hash[3] += v[3]; - ctx->hash[4] += v[4]; ctx->hash[5] += v[5]; - ctx->hash[6] += v[6]; ctx->hash[7] += v[7]; -} - -/* Compile 128 bytes of hash data into SHA256 digest value */ -/* NOTE: this routine assumes that the byte order in the */ -/* ctx->wbuf[] at this point is in such an order that low */ -/* address bytes in the ORIGINAL byte stream placed in this */ -/* buffer will now go to the high end of words on BOTH big */ -/* and little endian systems */ - -VOID_RETURN sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1]) -{ uint_32t pos = (uint_32t)(ctx->count[0] & SHA512_MASK), - space = SHA512_BLOCK_SIZE - pos; - const unsigned char *sp = data; - - if((ctx->count[0] += len) < len) - ++(ctx->count[1]); - - while(len >= space) /* tranfer whole blocks while possible */ - { - memcpy(((unsigned char*)ctx->wbuf) + pos, sp, space); - sp += space; len -= space; space = SHA512_BLOCK_SIZE; pos = 0; - bsw_64(ctx->wbuf, SHA512_BLOCK_SIZE >> 3); - sha512_compile(ctx); - } - - memcpy(((unsigned char*)ctx->wbuf) + pos, sp, len); -} - -/* SHA384/512 Final padding and digest calculation */ - -static void sha_end2(unsigned char hval[], sha512_ctx ctx[1], const unsigned int hlen) -{ uint_32t i = (uint_32t)(ctx->count[0] & SHA512_MASK); - - /* put bytes in the buffer in an order in which references to */ - /* 32-bit words will put bytes with lower addresses into the */ - /* top of 32 bit words on BOTH big and little endian machines */ - bsw_64(ctx->wbuf, (i + 7) >> 3); - - /* we now need to mask valid bytes and add the padding which is */ - /* a single 1 bit and as many zero bits as necessary. Note that */ - /* we can always add the first padding byte here because the */ - /* buffer always has at least one empty slot */ - ctx->wbuf[i >> 3] &= li_64(ffffffffffffff00) << 8 * (~i & 7); - ctx->wbuf[i >> 3] |= li_64(0000000000000080) << 8 * (~i & 7); - - /* we need 17 or more empty byte positions, one for the padding */ - /* byte (above) and sixteen for the length count. If there is */ - /* not enough space pad and empty the buffer */ - if(i > SHA512_BLOCK_SIZE - 17) - { - if(i < 120) ctx->wbuf[15] = 0; - sha512_compile(ctx); - i = 0; - } - else - i = (i >> 3) + 1; - - while(i < 14) - ctx->wbuf[i++] = 0; - - /* the following 64-bit length fields are assembled in the */ - /* wrong byte order on little endian machines but this is */ - /* corrected later since they are only ever used as 64-bit */ - /* word values. */ - ctx->wbuf[14] = (ctx->count[1] << 3) | (ctx->count[0] >> 61); - ctx->wbuf[15] = ctx->count[0] << 3; - sha512_compile(ctx); - - /* extract the hash value as bytes in case the hash buffer is */ - /* misaligned for 32-bit words */ - for(i = 0; i < hlen; ++i) - hval[i] = (unsigned char)(ctx->hash[i >> 3] >> (8 * (~i & 7))); -} - -#endif - -#if defined(SHA_384) - -/* SHA384 initialisation data */ - -const uint_64t i384[80] = -{ - li_64(cbbb9d5dc1059ed8), li_64(629a292a367cd507), - li_64(9159015a3070dd17), li_64(152fecd8f70e5939), - li_64(67332667ffc00b31), li_64(8eb44a8768581511), - li_64(db0c2e0d64f98fa7), li_64(47b5481dbefa4fa4) -}; - -VOID_RETURN sha384_begin(sha384_ctx ctx[1]) -{ - ctx->count[0] = ctx->count[1] = 0; - memcpy(ctx->hash, i384, 8 * sizeof(uint_64t)); -} - -VOID_RETURN sha384_end(unsigned char hval[], sha384_ctx ctx[1]) -{ - sha_end2(hval, ctx, SHA384_DIGEST_SIZE); -} - -VOID_RETURN sha384_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len) -{ sha384_ctx cx[1]; - - sha384_begin(cx); - sha384_hash(data, len, cx); - sha_end2(hval, cx, SHA384_DIGEST_SIZE); -} - -#endif - -#if defined(SHA_512) - -/* SHA512 initialisation data */ - -const uint_64t i512[80] = -{ - li_64(6a09e667f3bcc908), li_64(bb67ae8584caa73b), - li_64(3c6ef372fe94f82b), li_64(a54ff53a5f1d36f1), - li_64(510e527fade682d1), li_64(9b05688c2b3e6c1f), - li_64(1f83d9abfb41bd6b), li_64(5be0cd19137e2179) -}; - -VOID_RETURN sha512_begin(sha512_ctx ctx[1]) -{ - ctx->count[0] = ctx->count[1] = 0; - memcpy(ctx->hash, i512, 8 * sizeof(uint_64t)); -} - -VOID_RETURN sha512_end(unsigned char hval[], sha512_ctx ctx[1]) -{ - sha_end2(hval, ctx, SHA512_DIGEST_SIZE); -} - -VOID_RETURN sha512_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len) -{ sha512_ctx cx[1]; - - sha512_begin(cx); - sha512_hash(data, len, cx); - sha_end2(hval, cx, SHA512_DIGEST_SIZE); -} - -#endif - -#if defined(SHA_2) - -#define CTX_224(x) ((x)->uu->ctx256) -#define CTX_256(x) ((x)->uu->ctx256) -#define CTX_384(x) ((x)->uu->ctx512) -#define CTX_512(x) ((x)->uu->ctx512) - -/* SHA2 initialisation */ - -INT_RETURN sha2_begin(unsigned long len, sha2_ctx ctx[1]) -{ - switch(len) - { -#if defined(SHA_224) - case 224: - case 28: CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0; - memcpy(CTX_256(ctx)->hash, i224, 32); - ctx->sha2_len = 28; return EXIT_SUCCESS; -#endif -#if defined(SHA_256) - case 256: - case 32: CTX_256(ctx)->count[0] = CTX_256(ctx)->count[1] = 0; - memcpy(CTX_256(ctx)->hash, i256, 32); - ctx->sha2_len = 32; return EXIT_SUCCESS; -#endif -#if defined(SHA_384) - case 384: - case 48: CTX_384(ctx)->count[0] = CTX_384(ctx)->count[1] = 0; - memcpy(CTX_384(ctx)->hash, i384, 64); - ctx->sha2_len = 48; return EXIT_SUCCESS; -#endif -#if defined(SHA_512) - case 512: - case 64: CTX_512(ctx)->count[0] = CTX_512(ctx)->count[1] = 0; - memcpy(CTX_512(ctx)->hash, i512, 64); - ctx->sha2_len = 64; return EXIT_SUCCESS; -#endif - default: return EXIT_FAILURE; - } -} - -VOID_RETURN sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1]) -{ - switch(ctx->sha2_len) - { -#if defined(SHA_224) - case 28: sha224_hash(data, len, CTX_224(ctx)); return; -#endif -#if defined(SHA_256) - case 32: sha256_hash(data, len, CTX_256(ctx)); return; -#endif -#if defined(SHA_384) - case 48: sha384_hash(data, len, CTX_384(ctx)); return; -#endif -#if defined(SHA_512) - case 64: sha512_hash(data, len, CTX_512(ctx)); return; -#endif - } -} - -VOID_RETURN sha2_end(unsigned char hval[], sha2_ctx ctx[1]) -{ - switch(ctx->sha2_len) - { -#if defined(SHA_224) - case 28: sha_end1(hval, CTX_224(ctx), SHA224_DIGEST_SIZE); return; -#endif -#if defined(SHA_256) - case 32: sha_end1(hval, CTX_256(ctx), SHA256_DIGEST_SIZE); return; -#endif -#if defined(SHA_384) - case 48: sha_end2(hval, CTX_384(ctx), SHA384_DIGEST_SIZE); return; -#endif -#if defined(SHA_512) - case 64: sha_end2(hval, CTX_512(ctx), SHA512_DIGEST_SIZE); return; -#endif - } -} - -INT_RETURN sha2_all(unsigned char hval[], unsigned long size, - const unsigned char data[], unsigned long len) -{ sha2_ctx cx[1]; - - if(sha2_begin(size, cx) == EXIT_SUCCESS) - { - sha2_hash(data, len, cx); sha2_end(hval, cx); return EXIT_SUCCESS; - } - else - return EXIT_FAILURE; -} - -#endif - -#if defined(__cplusplus) -} -#endif diff --git a/libs/libks/crypt/sha2.h b/libs/libks/crypt/sha2.h deleted file mode 100644 index 873cda7764..0000000000 --- a/libs/libks/crypt/sha2.h +++ /dev/null @@ -1,151 +0,0 @@ -/* - --------------------------------------------------------------------------- - Copyright (c) 2002, Dr Brian Gladman, Worcester, UK. All rights reserved. - - LICENSE TERMS - - The free distribution and use of this software in both source and binary - form is allowed (with or without changes) provided that: - - 1. distributions of this source code include the above copyright - notice, this list of conditions and the following disclaimer; - - 2. distributions in binary form include the above copyright - notice, this list of conditions and the following disclaimer - in the documentation and/or other associated materials; - - 3. the copyright holder's name is not used to endorse products - built using this software without specific written permission. - - ALTERNATIVELY, provided that this notice is retained in full, this product - may be distributed under the terms of the GNU General Public License (GPL), - in which case the provisions of the GPL apply INSTEAD OF those given above. - - DISCLAIMER - - This software is provided 'as is' with no explicit or implied warranties - in respect of its properties, including, but not limited to, correctness - and/or fitness for purpose. - --------------------------------------------------------------------------- - Issue Date: 01/08/2005 -*/ - -#ifndef _SHA2_H -#define _SHA2_H - -#include - -#define SHA_64BIT - -/* define the hash functions that you need */ -#define SHA_2 /* for dynamic hash length */ -#define SHA_224 -#define SHA_256 -#ifdef SHA_64BIT -# define SHA_384 -# define SHA_512 -# define NEED_UINT_64T -#endif - -#include - -#if defined(__cplusplus) -extern "C" -{ -#endif - -/* Note that the following function prototypes are the same */ -/* for both the bit and byte oriented implementations. But */ -/* the length fields are in bytes or bits as is appropriate */ -/* for the version used. Bit sequences are arrays of bytes */ -/* in which bit sequence indexes increase from the most to */ -/* the least significant end of each byte */ - -#define SHA224_DIGEST_SIZE 28 -#define SHA224_BLOCK_SIZE 64 -#define SHA256_DIGEST_SIZE 32 -#define SHA256_BLOCK_SIZE 64 - -/* type to hold the SHA256 (and SHA224) context */ - -typedef struct -{ uint_32t count[2]; - uint_32t hash[8]; - uint_32t wbuf[16]; -} sha256_ctx; - -typedef sha256_ctx sha224_ctx; - -VOID_RETURN sha256_compile(sha256_ctx ctx[1]); - -VOID_RETURN sha224_begin(sha224_ctx ctx[1]); -#define sha224_hash sha256_hash -VOID_RETURN sha224_end(unsigned char hval[], sha224_ctx ctx[1]); -VOID_RETURN sha224_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len); - -VOID_RETURN sha256_begin(sha256_ctx ctx[1]); -VOID_RETURN sha256_hash(const unsigned char data[], unsigned long len, sha256_ctx ctx[1]); -VOID_RETURN sha256_end(unsigned char hval[], sha256_ctx ctx[1]); -VOID_RETURN sha256_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len); - -#ifndef SHA_64BIT - -typedef struct -{ union - { sha256_ctx ctx256[1]; - } uu[1]; - uint_32t sha2_len; -} sha2_ctx; - -#define SHA2_MAX_DIGEST_SIZE SHA256_DIGEST_SIZE - -#else - -#define SHA384_DIGEST_SIZE 48 -#define SHA384_BLOCK_SIZE 128 -#define SHA512_DIGEST_SIZE 64 -#define SHA512_BLOCK_SIZE 128 -#define SHA2_MAX_DIGEST_SIZE SHA512_DIGEST_SIZE - -/* type to hold the SHA384 (and SHA512) context */ - -typedef struct -{ uint_64t count[2]; - uint_64t hash[8]; - uint_64t wbuf[16]; -} sha512_ctx; - -typedef sha512_ctx sha384_ctx; - -typedef struct -{ union - { sha256_ctx ctx256[1]; - sha512_ctx ctx512[1]; - } uu[1]; - uint_32t sha2_len; -} sha2_ctx; - -VOID_RETURN sha512_compile(sha512_ctx ctx[1]); - -VOID_RETURN sha384_begin(sha384_ctx ctx[1]); -#define sha384_hash sha512_hash -VOID_RETURN sha384_end(unsigned char hval[], sha384_ctx ctx[1]); -VOID_RETURN sha384_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len); - -VOID_RETURN sha512_begin(sha512_ctx ctx[1]); -VOID_RETURN sha512_hash(const unsigned char data[], unsigned long len, sha512_ctx ctx[1]); -VOID_RETURN sha512_end(unsigned char hval[], sha512_ctx ctx[1]); -VOID_RETURN sha512_zrtp(unsigned char hval[], const unsigned char data[], unsigned long len); - -INT_RETURN sha2_begin(unsigned long size, sha2_ctx ctx[1]); -VOID_RETURN sha2_hash(const unsigned char data[], unsigned long len, sha2_ctx ctx[1]); -VOID_RETURN sha2_end(unsigned char hval[], sha2_ctx ctx[1]); -INT_RETURN sha2_all(unsigned char hval[], unsigned long size, const unsigned char data[], unsigned long len); - -#endif - -#if defined(__cplusplus) -} -#endif - -#endif diff --git a/libs/libks/crypt/twofish.c b/libs/libks/crypt/twofish.c deleted file mode 100644 index 45a07e2b22..0000000000 --- a/libs/libks/crypt/twofish.c +++ /dev/null @@ -1,1750 +0,0 @@ -/* - * Fast, portable, and easy-to-use Twofish implementation, - * Version 0.3. - * Copyright (c) 2002 by Niels Ferguson. - * (See further down for the almost-unrestricted licensing terms.) - * - * -------------------------------------------------------------------------- - * There are two files for this implementation: - * - twofish.h, the header file. - * - twofish.c, the code file. - * - * To incorporate this code into your program you should: - * - Check the licensing terms further down in this comment. - * - Fix the two type definitions in twofish.h to suit your platform. - * - Fix a few definitions in twofish.c in the section marked - * PLATFORM FIXES. There is one important ones that affects - * functionality, and then a few definitions that you can optimise - * for efficiency but those have no effect on the functionality. - * Don't change anything else. - * - Put the code in your project and compile it. - * - * To use this library you should: - * - Call Twofish_initialise() in your program before any other function in - * this library. - * - Use Twofish_prepare_key(...) to convert a key to internal form. - * - Use Twofish_encrypt(...) and Twofish_decrypt(...) to encrypt and decrypt - * data. - * See the comments in the header file for details on these functions. - * -------------------------------------------------------------------------- - * - * There are many Twofish implementation available for free on the web. - * Most of them are hard to integrate into your own program. - * As we like people to use our cipher, I thought I would make it easier. - * Here is a free and easy-to-integrate Twofish implementation in C. - * The latest version is always available from my personal home page at - * http://niels.ferguson.net/ - * - * Integrating library code into a project is difficult because the library - * header files interfere with the project's header files and code. - * And of course the project's header files interfere with the library code. - * I've tried to resolve these problems here. - * The header file of this implementation is very light-weight. - * It contains two typedefs, a structure, and a few function declarations. - * All names it defines start with "Twofish_". - * The header file is therefore unlikely to cause problems in your project. - * The code file of this implementation doesn't need to include the header - * files of the project. There is thus no danger of the project interfering - * with all the definitions and macros of the Twofish code. - * In most situations, all you need to do is fill in a few platform-specific - * definitions in the header file and code file, - * and you should be able to run the Twofish code in your project. - * I estimate it should take you less than an hour to integrate this code - * into your project, most of it spent reading the comments telling you what - * to do. - * - * For people using C++: it is very easy to wrap this library into a - * TwofishKey class. One of the big advantages is that you can automate the - * wiping of the key material in the destructor. I have not provided a C++ - * class because the interface depends too much on the abstract base class - * you use for block ciphers in your program, which I don't know about. - * - * This implementation is designed for use on PC-class machines. It uses the - * Twofish 'full' keying option which uses large tables. Total table size is - * around 5-6 kB for static tables plus 4.5 kB for each pre-processed key. - * If you need an implementation that uses less memory, - * take a look at Brian Gladman's code on his web site: - * http://fp.gladman.plus.com/cryptography_technology/aes/ - * He has code for all AES candidates. - * His Twofish code has lots of options trading off table size vs. speed. - * You can also take a look at the optimised code by Doug Whiting on the - * Twofish web site - * http://www.counterpane.com/twofish.html - * which has loads of options. - * I believe these existing implementations are harder to re-use because they - * are not clean libraries and they impose requirements on the environment. - * This implementation is very careful to minimise those, - * and should be easier to integrate into any larger program. - * - * The default mode of this implementation is fully portable as it uses no - * behaviour not defined in the C standard. (This is harder than you think.) - * If you have any problems porting the default mode, please let me know - * so that I can fix the problem. (But only if this code is at fault, I - * don't fix compilers.) - * Most of the platform fixes are related to non-portable but faster ways - * of implementing certain functions. - * - * In general I've tried to make the code as fast as possible, at the expense - * of memory and code size. However, C does impose limits, and this - * implementation will be slower than an optimised assembler implementation. - * But beware of assembler implementations: a good Pentium implementation - * uses completely different code than a good Pentium II implementation. - * You basically have to re-write the assembly code for every generation of - * processor. Unless you are severely pressed for speed, stick with C. - * - * The initialisation routine of this implementation contains a self-test. - * If initialisation succeeds without calling the fatal routine, then - * the implementation works. I don't think you can break the implementation - * in such a way that it still passes the tests, unless you are malicious. - * In other words: if the initialisation routine returns, - * you have successfully ported the implementation. - * (Or not implemented the fatal routine properly, but that is your problem.) - * - * I'm indebted to many people who helped me in one way or another to write - * this code. During the design of Twofish and the AES process I had very - * extensive discussions of all implementation issues with various people. - * Doug Whiting in particular provided a wealth of information. The Twofish - * team spent untold hours discussion various cipher features, and their - * implementation. Brian Gladman implemented all AES candidates in C, - * and we had some fruitful discussions on how to implement Twofish in C. - * Jan Nieuwenhuizen tested this code on Linux using GCC. - * - * Now for the license: - * The author hereby grants a perpetual license to everybody to - * use this code for any purpose as long as the copyright message is included - * in the source code of this or any derived work. - * - * Yes, this means that you, your company, your club, and anyone else - * can use this code anywhere you want. You can change it and distribute it - * under the GPL, include it in your commercial product without releasing - * the source code, put it on the web, etc. - * The only thing you cannot do is remove my copyright message, - * or distribute any source code based on this implementation that does not - * include my copyright message. - * - * I appreciate a mention in the documentation or credits, - * but I understand if that is difficult to do. - * I also appreciate it if you tell me where and why you used my code. - * - * Please send any questions or comments to niels@ferguson.net - * - * Have Fun! - * - * Niels - */ - -/* - * DISCLAIMER: As I'm giving away my work for free, I'm of course not going - * to accept any liability of any form. This code, or the Twofish cipher, - * might very well be flawed; you have been warned. - * This software is provided as-is, without any kind of warrenty or - * guarantee. And that is really all you can expect when you download - * code for free from the Internet. - * - * I think it is really sad that disclaimers like this seem to be necessary. - * If people only had a little bit more common sense, and didn't come - * whining like little children every time something happens.... - */ - -/* - * Version history: - * Version 0.0, 2002-08-30 - * First written. - * Version 0.1, 2002-09-03 - * Added disclaimer. Improved self-tests. - * Version 0.2, 2002-09-09 - * Removed last non-portabilities. Default now works completely within - * the C standard. UInt32 can be larger than 32 bits without problems. - * Version 0.3, 2002-09-28 - * Bugfix: use instead of to adhere to ANSI/ISO. - * Rename BIG_ENDIAN macro to CPU_IS_BIG_ENDIAN. The gcc library - * header already defines BIG_ENDIAN, even though it is not - * supposed to. - */ - - -/* - * Minimum set of include files. - * You should not need any application-specific include files for this code. - * In fact, adding you own header files could break one of the many macros or - * functions in this file. Be very careful. - * Standard include files will probably be ok. - */ -#include -#include -#include -/* #include * for memset(), memcpy(), and memcmp() */ -#include "twofish.h" - - -/* - * PLATFORM FIXES - * ============== - * - * Fix the type definitions in twofish.h first! - * - * The following definitions have to be fixed for each particular platform - * you work on. If you have a multi-platform program, you no doubt have - * portable definitions that you can substitute here without changing the - * rest of the code. - */ - - -/* - * Function called if something is fatally wrong with the implementation. - * This fatal function is called when a coding error is detected in the - * Twofish implementation, or when somebody passes an obviously erroneous - * parameter to this implementation. There is not much you can do when - * the code contains bugs, so we just stop. - * - * The argument is a string. Ideally the fatal function prints this string - * as an error message. Whatever else this function does, it should never - * return. A typical implementation would stop the program completely after - * printing the error message. - * - * This default implementation is not very useful, - * but does not assume anything about your environment. - * It will at least let you know something is wrong.... - * I didn't want to include any libraries to print and error or so, - * as this makes the code much harder to integrate in a project. - * - * Note that the Twofish_fatal function may not return to the caller. - * Unfortunately this is not something the self-test can test for, - * so you have to make sure of this yourself. - * - * If you want to call an external function, be careful about including - * your own header files here. This code uses a lot of macros, and your - * header file could easily break it. Maybe the best solution is to use - * a separate extern statement for your fatal function. - */ -/* #define Twofish_fatal(pmsgx) { fprintf(stderr, pmsgx); exit(1); } */ -#define Twofish_fatal(pmsgx, code) { return(code); } - - -/* - * The rest of the settings are not important for the functionality - * of this Twofish implementation. That is, their default settings - * work on all platforms. You can change them to improve the - * speed of the implementation on your platform. Erroneous settings - * will result in erroneous implementations, but the self-test should - * catch those. - */ - - -/* - * Macros to rotate a Twofish_UInt32 value left or right by the - * specified number of bits. This should be a 32-bit rotation, - * and not rotation of, say, 64-bit values. - * - * Every encryption or decryption operation uses 32 of these rotations, - * so it is a good idea to make these macros efficient. - * - * This fully portable definition has one piece of tricky stuff. - * The UInt32 might be larger than 32 bits, so we have to mask - * any higher bits off. The simplest way to do this is to 'and' the - * value first with 0xffffffff and then shift it right. An optimising - * compiler that has a 32-bit type can optimise this 'and' away. - * - * Unfortunately there is no portable way of writing the constant - * 0xffffffff. You don't know which suffix to use (U, or UL?) - * The UINT32_MASK definition uses a bit of trickery. Shift-left - * is only defined if the shift amount is strictly less than the size - * of the UInt32, so we can't use (1<<32). The answer it to take the value - * 2, cast it to a UInt32, shift it left 31 positions, and subtract one. - * Another example of how to make something very simple extremely difficult. - * I hate C. - * - * The rotation macros are straightforward. - * They are only applied to UInt32 values, which are _unsigned_ - * so the >> operator must do a logical shift that brings in zeroes. - * On most platforms you will only need to optimise the ROL32 macro; the - * ROR32 macro is not inefficient on an optimising compiler as all rotation - * amounts in this code are known at compile time. - * - * On many platforms there is a faster solution. - * For example, MS compilers have the __rotl and __rotr functions - * that generate x86 rotation instructions. - */ -#define UINT32_MASK ( (((Twofish_UInt32)2)<<31) - 1 ) - -#ifndef _MSC_VER -#define ROL32(x,n) ( (x)<<(n) | ((x) & UINT32_MASK) >> (32-(n)) ) -#define ROR32(x,n) ( (x)>>(n) | ((x) & UINT32_MASK) << (32-(n)) ) -#else -#define ROL32(x,n) (_lrotl((x), (n))) -#define ROR32(x,n) (_lrotr((x), (n))) -#endif - -/* - * Select data type for q-table entries. - * - * Larger entry types cost more memory (1.5 kB), and might be faster - * or slower depending on the CPU and compiler details. - * - * This choice only affects the static data size and the key setup speed. - * Functionality, expanded key size, or encryption speed are not affected. - * Define to 1 to get large q-table entries. - */ -#define LARGE_Q_TABLE 0 /* default = 0 */ - - -/* - * Method to select a single byte from a UInt32. - * WARNING: non-portable code if set; might not work on all platforms. - * - * Inside the inner loop of Twofish it is necessary to access the 4 - * individual bytes of a UInt32. This can be done using either shifts - * and masks, or memory accesses. - * - * Set to 0 to use shift and mask operations for the byte selection. - * This is more ALU intensive. It is also fully portable. - * - * Set to 1 to use memory accesses. The UInt32 is stored in memory and - * the individual bytes are read from memory one at a time. - * This solution is more memory-intensive, and not fully portable. - * It might be faster on your platform, or not. If you use this option, - * make sure you set the CPU_IS_BIG_ENDIAN flag appropriately. - * - * This macro does not affect the conversion of the inputs and outputs - * of the cipher. See the CONVERT_USING_CASTS macro for that. - */ -#define SELECT_BYTE_FROM_UINT32_IN_MEMORY 0 /* default = 0 */ - - -/* - * Method used to read the input and write the output. - * WARNING: non-portable code if set; might not work on all platforms. - * - * Twofish operates on 32-bit words. The input to the cipher is - * a byte array, as is the output. The portable method of doing the - * conversion is a bunch of rotate and mask operations, but on many - * platforms it can be done faster using a cast. - * This only works if your CPU allows UInt32 accesses to arbitrary Byte - * addresses. - * - * Set to 0 to use the shift and mask operations. This is fully - * portable. . - * - * Set to 1 to use a cast. The Byte * is cast to a UInt32 *, and a - * UInt32 is read. If necessary (as indicated by the CPU_IS_BIG_ENDIAN - * macro) the byte order in the UInt32 is swapped. The reverse is done - * to write the output of the encryption/decryption. Make sure you set - * the CPU_IS_BIG_ENDIAN flag appropriately. - * This option does not work unless a UInt32 is exactly 32 bits. - * - * This macro only changes the reading/writing of the plaintext/ciphertext. - * See the SELECT_BYTE_FROM_UINT32_IN_MEMORY to affect the way in which - * a UInt32 is split into 4 bytes for the S-box selection. - */ -#define CONVERT_USING_CASTS 0 /* default = 0 */ - - -/* - * Endianness switch. - * Only relevant if SELECT_BYTE_FROM_UINT32_IN_MEMORY or - * CONVERT_USING_CASTS is set. - * - * Set to 1 on a big-endian machine, and to 0 on a little-endian machine. - * Twofish uses the little-endian convention (least significant byte first) - * and big-endian machines (using most significant byte first) - * have to do a few conversions. - * - * CAUTION: This code has never been tested on a big-endian machine, - * because I don't have access to one. Feedback appreciated. - */ -#define CPU_IS_BIG_ENDIAN 0 - - -/* - * Macro to reverse the order of the bytes in a UInt32. - * Used to convert to little-endian on big-endian machines. - * This macro is always tested, but only used in the encryption and - * decryption if CONVERT_USING_CASTS, and CPU_IS_BIG_ENDIAN - * are both set. In other words: this macro is only speed-critical if - * both these flags have been set. - * - * This default definition of SWAP works, but on many platforms there is a - * more efficient implementation. - */ -#define BSWAP(x) ((ROL32((x),8)&0x00ff00ff) | (ROR32((x),8) & 0xff00ff00)) - - -/* - * END OF PLATFORM FIXES - * ===================== - * - * You should not have to touch the rest of this file. - */ - - -/* - * Convert the external type names to some that are easier to use inside - * this file. I didn't want to use the names Byte and UInt32 in the - * header file, because many programs already define them and using two - * conventions at once can be very difficult. - * Don't change these definitions! Change the originals - * in twofish.h instead. - */ -/* A Byte must be an unsigned integer, 8 bits long. */ -/* typedef Twofish_Byte Byte; */ -/* A UInt32 must be an unsigned integer at least 32 bits long. */ -/* typedef Twofish_UInt32 UInt32; */ - - -/* - * Define a macro ENDIAN_CONVERT. - * - * We define a macro ENDIAN_CONVERT that performs a BSWAP on big-endian - * machines, and is the identity function on little-endian machines. - * The code then uses this macro without considering the endianness. - */ - -#if CPU_IS_BIG_ENDIAN -#define ENDIAN_CONVERT(x) BSWAP(x) -#else -#define ENDIAN_CONVERT(x) (x) -#endif - - -/* - * Compute byte offset within a UInt32 stored in memory. - * - * This is only used when SELECT_BYTE_FROM_UINT32_IN_MEMORY is set. - * - * The input is the byte number 0..3, 0 for least significant. - * Note the use of sizeof() to support UInt32 types that are larger - * than 4 bytes. - */ -#if CPU_IS_BIG_ENDIAN -#define BYTE_OFFSET( n ) (sizeof(Twofish_UInt32) - 1 - (n) ) -#else -#define BYTE_OFFSET( n ) (n) -#endif - - -/* - * Macro to get Byte no. b from UInt32 value X. - * We use two different definition, depending on the settings. - */ -#if SELECT_BYTE_FROM_UINT32_IN_MEMORY - /* Pick the byte from the memory in which X is stored. */ -#define SELECT_BYTE( X, b ) (((Twofish_Byte *)(&(X)))[BYTE_OFFSET(b)]) -#else - /* Portable solution: Pick the byte directly from the X value. */ -#define SELECT_BYTE( X, b ) (((X) >> (8*(b))) & 0xff) -#endif - - -/* Some shorthands because we use byte selection in large formulae. */ -#define b0(X) SELECT_BYTE((X),0) -#define b1(X) SELECT_BYTE((X),1) -#define b2(X) SELECT_BYTE((X),2) -#define b3(X) SELECT_BYTE((X),3) - - -/* - * We need macros to load and store UInt32 from/to byte arrays - * using the least-significant-byte-first convention. - * - * GET32( p ) gets a UInt32 in lsb-first form from four bytes pointed to - * by p. - * PUT32( v, p ) writes the UInt32 value v at address p in lsb-first form. - */ -#if CONVERT_USING_CASTS - - /* Get UInt32 from four bytes pointed to by p. */ -#define GET32( p ) ENDIAN_CONVERT( *((Twofish_UInt32 *)(p)) ) - /* Put UInt32 into four bytes pointed to by p */ -#define PUT32( v, p ) *((Twofish_UInt32 *)(p)) = ENDIAN_CONVERT(v) - -#else - - /* Get UInt32 from four bytes pointed to by p. */ -#define GET32( p ) \ - ( \ - (Twofish_UInt32)((p)[0]) \ - | (Twofish_UInt32)((p)[1])<< 8 \ - | (Twofish_UInt32)((p)[2])<<16 \ - | (Twofish_UInt32)((p)[3])<<24 \ - ) - /* Put UInt32 into four bytes pointed to by p */ -#define PUT32( v, p ) \ - (p)[0] = (Twofish_Byte)(((v) ) & 0xff); \ - (p)[1] = (Twofish_Byte)(((v) >> 8) & 0xff); \ - (p)[2] = (Twofish_Byte)(((v) >> 16) & 0xff); \ - (p)[3] = (Twofish_Byte)(((v) >> 24) & 0xff) - -#endif - -#ifdef ANDROID -/** - * Dummy function to disable some compiler optimizations. - * - * See comment in Twofish_cfb128_encrypt(). - */ -void Two_debugDummy(Twofish_Byte* in, Twofish_Byte* out, Twofish_Byte* ivec) -{ -} -#endif -/* - * Test the platform-specific macros. - * This function tests the macros defined so far to make sure the - * definitions are appropriate for this platform. - * If you make any mistake in the platform configuration, this should detect - * that and inform you what went wrong. - * Somewhere, someday, this is going to save somebody a lot of time, - * because misbehaving macros are hard to debug. - */ -static int test_platform() - { - /* Buffer with test values. */ - Twofish_Byte buf[] = {0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0}; - Twofish_UInt32 C; - Twofish_UInt32 x,y; - int i; - - /* - * Some sanity checks on the types that can't be done in compile time. - * A smart compiler will just optimise these tests away. - * The pre-processor doesn't understand different types, so we cannot - * do these checks in compile-time. - * - * I hate C. - * - * The first check in each case is to make sure the size is correct. - * The second check is to ensure that it is an unsigned type. - */ - if( ((Twofish_UInt32)((Twofish_UInt32)1 << 31) == 0) || ((Twofish_UInt32)-1 < 0 )) - { - Twofish_fatal( "Twofish code: Twofish_UInt32 type not suitable", ERR_UINT32 ); - } - if( (sizeof( Twofish_Byte ) != 1) || (((Twofish_Byte)-1) < 0) ) - { - Twofish_fatal( "Twofish code: Twofish_Byte type not suitable", ERR_BYTE ); - } - - /* - * Sanity-check the endianness conversions. - * This is just an aid to find problems. If you do the endianness - * conversion macros wrong you will fail the full cipher test, - * but that does not help you find the error. - * Always make it easy to find the bugs! - * - * Detail: There is no fully portable way of writing UInt32 constants, - * as you don't know whether to use the U or UL suffix. Using only U you - * might only be allowed 16-bit constants. Using UL you might get 64-bit - * constants which cannot be stored in a UInt32 without warnings, and - * which generally behave subtly different from a true UInt32. - * As long as we're just comparing with the constant, - * we can always use the UL suffix and at worst lose some efficiency. - * I use a separate '32-bit constant' macro in most of my other code. - * - * I hate C. - * - * Start with testing GET32. We test it on all positions modulo 4 - * to make sure we can handly any position of inputs. (Some CPUs - * do not allow non-aligned accesses which we would do if you used - * the CONVERT_USING_CASTS option. - */ - if( (GET32( buf ) != 0x78563412UL) || (GET32(buf+1) != 0x9a785634UL) - || (GET32( buf+2 ) != 0xbc9a7856UL) || (GET32(buf+3) != 0xdebc9a78UL) ) - { - Twofish_fatal( "Twofish code: GET32 not implemented properly", ERR_GET32 ); - } - - /* - * We can now use GET32 to test PUT32. - * We don't test the shifted versions. If GET32 can do that then - * so should PUT32. - */ - C = GET32( buf ); - PUT32( 3*C, buf ); - if( GET32( buf ) != 0x69029c36UL ) - { - Twofish_fatal( "Twofish code: PUT32 not implemented properly", ERR_PUT32 ); - } - - - /* Test ROL and ROR */ - for( i=1; i<32; i++ ) - { - /* Just a simple test. */ - x = ROR32( C, i ); - y = ROL32( C, i ); - x ^= (C>>i) ^ (C<<(32-i)); - /*y ^= (C<>(32-i)); */ - y ^= (C<>(32-i)); - x |= y; - /* - * Now all we check is that x is zero in the least significant - * 32 bits. Using the UL suffix is safe here, as it doesn't matter - * if we get a larger type. - */ - if( (x & 0xffffffffUL) != 0 ) - { - Twofish_fatal( "Twofish ROL or ROR not properly defined.", ERR_ROLR ); - } - } - - /* Test the BSWAP macro */ - if( BSWAP(C) != 0x12345678UL ) - { - /* - * The BSWAP macro should always work, even if you are not using it. - * A smart optimising compiler will just remove this entire test. - */ - Twofish_fatal( "BSWAP not properly defined.", ERR_BSWAP ); - } - - /* And we can test the b macros which use SELECT_BYTE. */ - if( (b0(C)!=0x12) || (b1(C) != 0x34) || (b2(C) != 0x56) || (b3(C) != 0x78) ) - { - /* - * There are many reasons why this could fail. - * Most likely is that CPU_IS_BIG_ENDIAN has the wrong value. - */ - Twofish_fatal( "Twofish code: SELECT_BYTE not implemented properly", ERR_SELECTB ); - } - return SUCCESS; - } - - -/* - * Finally, we can start on the Twofish-related code. - * You really need the Twofish specifications to understand this code. The - * best source is the Twofish book: - * "The Twofish Encryption Algorithm", by Bruce Schneier, John Kelsey, - * Doug Whiting, David Wagner, Chris Hall, and Niels Ferguson. - * you can also use the AES submission document of Twofish, which is - * available from my list of publications on my personal web site at - * http://niels.ferguson.net/. - * - * The first thing we do is write the testing routines. This is what the - * implementation has to satisfy in the end. We only test the external - * behaviour of the implementation of course. - */ - - -/* - * Perform a single self test on a (plaintext,ciphertext,key) triple. - * Arguments: - * key array of key bytes - * key_len length of key in bytes - * p plaintext - * c ciphertext - */ -static int test_vector( Twofish_Byte key[], int key_len, Twofish_Byte p[16], Twofish_Byte c[16] ) - { - Twofish_Byte tmp[16]; /* scratch pad. */ - Twofish_key xkey; /* The expanded key */ - int i; - - - /* Prepare the key */ - if ((i = Twofish_prepare_key( key, key_len, &xkey)) < 0) - return i; - - /* - * We run the test twice to ensure that the xkey structure - * is not damaged by the first encryption. - * Those are hideous bugs to find if you get them in an application. - */ - for( i=0; i<2; i++ ) - { - /* Encrypt and test */ - Twofish_encrypt( &xkey, p, tmp ); - if( memcmp( c, tmp, 16 ) != 0 ) - { - Twofish_fatal( "Twofish encryption failure", ERR_TEST_ENC ); - } - - /* Decrypt and test */ - Twofish_decrypt( &xkey, c, tmp ); - if( memcmp( p, tmp, 16 ) != 0 ) - { - Twofish_fatal( "Twofish decryption failure", ERR_TEST_DEC ); - } - } - - /* The test keys are not secret, so we don't need to wipe xkey. */ - return SUCCESS; - } - - -/* - * Check implementation using three (key,plaintext,ciphertext) - * test vectors, one for each major key length. - * - * This is an absolutely minimal self-test. - * This routine does not test odd-sized keys. - */ -static int test_vectors() - { - /* - * We run three tests, one for each major key length. - * These test vectors come from the Twofish specification. - * One encryption and one decryption using randomish data and key - * will detect almost any error, especially since we generate the - * tables ourselves, so we don't have the problem of a single - * damaged table entry in the source. - */ - - /* 128-bit test is the I=3 case of section B.2 of the Twofish book. */ - static Twofish_Byte k128[] = { - 0x9F, 0x58, 0x9F, 0x5C, 0xF6, 0x12, 0x2C, 0x32, - 0xB6, 0xBF, 0xEC, 0x2F, 0x2A, 0xE8, 0xC3, 0x5A, - }; - static Twofish_Byte p128[] = { - 0xD4, 0x91, 0xDB, 0x16, 0xE7, 0xB1, 0xC3, 0x9E, - 0x86, 0xCB, 0x08, 0x6B, 0x78, 0x9F, 0x54, 0x19 - }; - static Twofish_Byte c128[] = { - 0x01, 0x9F, 0x98, 0x09, 0xDE, 0x17, 0x11, 0x85, - 0x8F, 0xAA, 0xC3, 0xA3, 0xBA, 0x20, 0xFB, 0xC3 - }; - - /* 192-bit test is the I=4 case of section B.2 of the Twofish book. */ - static Twofish_Byte k192[] = { - 0x88, 0xB2, 0xB2, 0x70, 0x6B, 0x10, 0x5E, 0x36, - 0xB4, 0x46, 0xBB, 0x6D, 0x73, 0x1A, 0x1E, 0x88, - 0xEF, 0xA7, 0x1F, 0x78, 0x89, 0x65, 0xBD, 0x44 - }; - static Twofish_Byte p192[] = { - 0x39, 0xDA, 0x69, 0xD6, 0xBA, 0x49, 0x97, 0xD5, - 0x85, 0xB6, 0xDC, 0x07, 0x3C, 0xA3, 0x41, 0xB2 - }; - static Twofish_Byte c192[] = { - 0x18, 0x2B, 0x02, 0xD8, 0x14, 0x97, 0xEA, 0x45, - 0xF9, 0xDA, 0xAC, 0xDC, 0x29, 0x19, 0x3A, 0x65 - }; - - /* 256-bit test is the I=4 case of section B.2 of the Twofish book. */ - static Twofish_Byte k256[] = { - 0xD4, 0x3B, 0xB7, 0x55, 0x6E, 0xA3, 0x2E, 0x46, - 0xF2, 0xA2, 0x82, 0xB7, 0xD4, 0x5B, 0x4E, 0x0D, - 0x57, 0xFF, 0x73, 0x9D, 0x4D, 0xC9, 0x2C, 0x1B, - 0xD7, 0xFC, 0x01, 0x70, 0x0C, 0xC8, 0x21, 0x6F - }; - static Twofish_Byte p256[] = { - 0x90, 0xAF, 0xE9, 0x1B, 0xB2, 0x88, 0x54, 0x4F, - 0x2C, 0x32, 0xDC, 0x23, 0x9B, 0x26, 0x35, 0xE6 - }; - static Twofish_Byte c256[] = { - 0x6C, 0xB4, 0x56, 0x1C, 0x40, 0xBF, 0x0A, 0x97, - 0x05, 0x93, 0x1C, 0xB6, 0xD4, 0x08, 0xE7, 0xFA - }; - - int ret; - - /* Run the actual tests. */ - if ((ret = test_vector( k128, 16, p128, c128 )) < 0) - return ret; - if ((ret = test_vector( k192, 24, p192, c192 )) < 0) - return ret; - if ((ret = test_vector( k256, 32, p256, c256 )) < 0) - return ret; - return SUCCESS; - } - - -/* - * Perform extensive test for a single key size. - * - * Test a single key size against the test vectors from section - * B.2 in the Twofish book. This is a sequence of 49 encryptions - * and decryptions. Each plaintext is equal to the ciphertext of - * the previous encryption. The key is made up from the ciphertext - * two and three encryptions ago. Both plaintext and key start - * at the zero value. - * We should have designed a cleaner recurrence relation for - * these tests, but it is too late for that now. At least we learned - * how to do it better next time. - * For details see appendix B of the book. - * - * Arguments: - * key_len Number of bytes of key - * final_value Final plaintext value after 49 iterations - */ -static int test_sequence( int key_len, Twofish_Byte final_value[] ) - { - Twofish_Byte buf[ (50+3)*16 ]; /* Buffer to hold our computation values. */ - Twofish_Byte tmp[16]; /* Temp for testing the decryption. */ - Twofish_key xkey; /* The expanded key */ - int i, ret; - Twofish_Byte * p; - - /* Wipe the buffer */ - memset( buf, 0, sizeof( buf ) ); - - /* - * Because the recurrence relation is done in an inconvenient manner - * we end up looping backwards over the buffer. - */ - - /* Pointer in buffer points to current plaintext. */ - p = &buf[50*16]; - for( i=1; i<50; i++ ) - { - /* - * Prepare a key. - * This automatically checks that key_len is valid. - */ - if ((ret = Twofish_prepare_key( p+16, key_len, &xkey)) < 0) - return ret; - - /* Compute the next 16 bytes in the buffer */ - Twofish_encrypt( &xkey, p, p-16 ); - - /* Check that the decryption is correct. */ - Twofish_decrypt( &xkey, p-16, tmp ); - if( memcmp( tmp, p, 16 ) != 0 ) - { - Twofish_fatal( "Twofish decryption failure in sequence", ERR_SEQ_DEC ); - } - /* Move on to next 16 bytes in the buffer. */ - p -= 16; - } - - /* And check the final value. */ - if( memcmp( p, final_value, 16 ) != 0 ) - { - Twofish_fatal( "Twofish encryption failure in sequence", ERR_SEQ_ENC ); - } - - /* None of the data was secret, so there is no need to wipe anything. */ - return SUCCESS; - } - - -/* - * Run all three sequence tests from the Twofish test vectors. - * - * This checks the most extensive test vectors currently available - * for Twofish. The data is from the Twofish book, appendix B.2. - */ -static int test_sequences() - { - static Twofish_Byte r128[] = { - 0x5D, 0x9D, 0x4E, 0xEF, 0xFA, 0x91, 0x51, 0x57, - 0x55, 0x24, 0xF1, 0x15, 0x81, 0x5A, 0x12, 0xE0 - }; - static Twofish_Byte r192[] = { - 0xE7, 0x54, 0x49, 0x21, 0x2B, 0xEE, 0xF9, 0xF4, - 0xA3, 0x90, 0xBD, 0x86, 0x0A, 0x64, 0x09, 0x41 - }; - static Twofish_Byte r256[] = { - 0x37, 0xFE, 0x26, 0xFF, 0x1C, 0xF6, 0x61, 0x75, - 0xF5, 0xDD, 0xF4, 0xC3, 0x3B, 0x97, 0xA2, 0x05 - }; - - /* Run the three sequence test vectors */ - int ret; - if ((ret = test_sequence( 16, r128)) < 0) - return ret; - if ((ret = test_sequence( 24, r192)) < 0) - return ret; - if ((ret = test_sequence( 32, r256)) < 0) - return ret; - return SUCCESS; - } - - -/* - * Test the odd-sized keys. - * - * Every odd-sized key is equivalent to a one of 128, 192, or 256 bits. - * The equivalent key is found by padding at the end with zero bytes - * until a regular key size is reached. - * - * We just test that the key expansion routine behaves properly. - * If the expanded keys are identical, then the encryptions and decryptions - * will behave the same. - */ -static int test_odd_sized_keys() - { - Twofish_Byte buf[32]; - Twofish_key xkey; - Twofish_key xkey_two; - int i, ret; - - /* - * We first create an all-zero key to use as PRNG key. - * Normally we would not have to fill the buffer with zeroes, as we could - * just pass a zero key length to the Twofish_prepare_key function. - * However, this relies on using odd-sized keys, and those are just the - * ones we are testing here. We can't use an untested function to test - * itself. - */ - memset( buf, 0, sizeof( buf ) ); - if ((ret = Twofish_prepare_key( buf, 16, &xkey)) < 0) - return ret; - - /* Fill buffer with pseudo-random data derived from two encryptions */ - Twofish_encrypt( &xkey, buf, buf ); - Twofish_encrypt( &xkey, buf, buf+16 ); - - /* Create all possible shorter keys that are prefixes of the buffer. */ - for( i=31; i>=0; i-- ) - { - /* Set a byte to zero. This is the new padding byte */ - buf[i] = 0; - - /* Expand the key with only i bytes of length */ - if ((ret = Twofish_prepare_key( buf, i, &xkey)) < 0) - return ret; - - /* Expand the corresponding padded key of regular length */ - if ((ret = Twofish_prepare_key( buf, i<=16 ? 16 : (i<= 24 ? 24 : 32), &xkey_two )) < 0) - return ret; - - /* Compare the two */ - if( memcmp( &xkey, &xkey_two, sizeof( xkey ) ) != 0 ) - { - Twofish_fatal( "Odd sized keys do not expand properly", ERR_ODD_KEY ); - } - } - - /* None of the key values are secret, so we don't need to wipe them. */ - return SUCCESS; - } - - -/* - * Test the Twofish implementation. - * - * This routine runs all the self tests, in order of importance. - * It is called by the Twofish_initialise routine. - * - * In almost all applications the cost of running the self tests during - * initialisation is insignificant, especially - * compared to the time it takes to load the application from disk. - * If you are very pressed for initialisation performance, - * you could remove some of the tests. Make sure you did run them - * once in the software and hardware configuration you are using. - */ -static int self_test() - { - int ret; - /* The three test vectors form an absolute minimal test set. */ - if ((ret = test_vectors()) < 0) - return ret; - - /* - * If at all possible you should run these tests too. They take - * more time, but provide a more thorough coverage. - */ - if ((ret = test_sequences()) < 0) - return ret; - - /* Test the odd-sized keys. */ - if ((ret = test_odd_sized_keys()) < 0) - return ret; - return SUCCESS; - } - - -/* - * And now, the actual Twofish implementation. - * - * This implementation generates all the tables during initialisation. - * I don't like large tables in the code, especially since they are easily - * damaged in the source without anyone noticing it. You need code to - * generate them anyway, and this way all the code is close together. - * Generating them in the application leads to a smaller executable - * (the code is smaller than the tables it generates) and a - * larger static memory footprint. - * - * Twofish can be implemented in many ways. I have chosen to - * use large tables with a relatively long key setup time. - * If you encrypt more than a few blocks of data it pays to pre-compute - * as much as possible. This implementation is relatively inefficient for - * applications that need to re-key every block or so. - */ - -/* - * We start with the t-tables, directly from the Twofish definition. - * These are nibble-tables, but merging them and putting them two nibbles - * in one byte is more work than it is worth. - */ -static Twofish_Byte t_table[2][4][16] = { - { - {0x8,0x1,0x7,0xD,0x6,0xF,0x3,0x2,0x0,0xB,0x5,0x9,0xE,0xC,0xA,0x4}, - {0xE,0xC,0xB,0x8,0x1,0x2,0x3,0x5,0xF,0x4,0xA,0x6,0x7,0x0,0x9,0xD}, - {0xB,0xA,0x5,0xE,0x6,0xD,0x9,0x0,0xC,0x8,0xF,0x3,0x2,0x4,0x7,0x1}, - {0xD,0x7,0xF,0x4,0x1,0x2,0x6,0xE,0x9,0xB,0x3,0x0,0x8,0x5,0xC,0xA} - }, - { - {0x2,0x8,0xB,0xD,0xF,0x7,0x6,0xE,0x3,0x1,0x9,0x4,0x0,0xA,0xC,0x5}, - {0x1,0xE,0x2,0xB,0x4,0xC,0x3,0x7,0x6,0xD,0xA,0x5,0xF,0x9,0x0,0x8}, - {0x4,0xC,0x7,0x5,0x1,0x6,0x9,0xA,0x0,0xE,0xD,0x8,0x2,0xB,0x3,0xF}, - {0xB,0x9,0x5,0x1,0xC,0x3,0xD,0xE,0x6,0x4,0x7,0xF,0x2,0x0,0x8,0xA} - } -}; - - -/* A 1-bit rotation of 4-bit values. Input must be in range 0..15 */ -#define ROR4BY1( x ) (((x)>>1) | (((x)<<3) & 0x8) ) - -/* - * The q-boxes are only used during the key schedule computations. - * These are 8->8 bit lookup tables. Some CPUs prefer to have 8->32 bit - * lookup tables as it is faster to load a 32-bit value than to load an - * 8-bit value and zero the rest of the register. - * The LARGE_Q_TABLE switch allows you to choose 32-bit entries in - * the q-tables. Here we just define the Qtype which is used to store - * the entries of the q-tables. - */ -#if LARGE_Q_TABLE -typedef Twofish_UInt32 Qtype; -#else -typedef Twofish_Byte Qtype; -#endif - -/* - * The actual q-box tables. - * There are two q-boxes, each having 256 entries. - */ -static Qtype q_table[2][256]; - - -/* - * Now the function that converts a single t-table into a q-table. - * - * Arguments: - * t[4][16] : four 4->4bit lookup tables that define the q-box - * q[256] : output parameter: the resulting q-box as a lookup table. - */ -static void make_q_table( Twofish_Byte t[4][16], Qtype q[256] ) - { - int ae,be,ao,bo; /* Some temporaries. */ - int i; - /* Loop over all input values and compute the q-box result. */ - for( i=0; i<256; i++ ) { - /* - * This is straight from the Twofish specifications. - * - * The ae variable is used for the a_i values from the specs - * with even i, and ao for the odd i's. Similarly for the b's. - */ - ae = i>>4; be = i&0xf; - ao = ae ^ be; bo = ae ^ ROR4BY1(be) ^ ((ae<<3)&8); - ae = t[0][ao]; be = t[1][bo]; - ao = ae ^ be; bo = ae ^ ROR4BY1(be) ^ ((ae<<3)&8); - ae = t[2][ao]; be = t[3][bo]; - - /* Store the result in the q-box table, the cast avoids a warning. */ - q[i] = (Qtype) ((be<<4) | ae); - } - } - - -/* - * Initialise both q-box tables. - */ -static void initialise_q_boxes() { - /* Initialise each of the q-boxes using the t-tables */ - make_q_table( t_table[0], q_table[0] ); - make_q_table( t_table[1], q_table[1] ); - } - - -/* - * Next up is the MDS matrix multiplication. - * The MDS matrix multiplication operates in the field - * GF(2)[x]/p(x) with p(x)=x^8+x^6+x^5+x^3+1. - * If you don't understand this, read a book on finite fields. You cannot - * follow the finite-field computations without some background. - * - * In this field, multiplication by x is easy: shift left one bit - * and if bit 8 is set then xor the result with 0x169. - * - * The MDS coefficients use a multiplication by 1/x, - * or rather a division by x. This is easy too: first make the - * value 'even' (i.e. bit 0 is zero) by xorring with 0x169 if necessary, - * and then shift right one position. - * Even easier: shift right and xor with 0xb4 if the lsbit was set. - * - * The MDS coefficients are 1, EF, and 5B, and we use the fact that - * EF = 1 + 1/x + 1/x^2 - * 5B = 1 + 1/x^2 - * in this field. This makes multiplication by EF and 5B relatively easy. - * - * This property is no accident, the MDS matrix was designed to allow - * this implementation technique to be used. - * - * We have four MDS tables, each mapping 8 bits to 32 bits. - * Each table performs one column of the matrix multiplication. - * As the MDS is always preceded by q-boxes, each of these tables - * also implements the q-box just previous to that column. - */ - -/* The actual MDS tables. */ -static Twofish_UInt32 MDS_table[4][256]; - -/* A small table to get easy conditional access to the 0xb4 constant. */ -static Twofish_UInt32 mds_poly_divx_const[] = {0,0xb4}; - -/* Function to initialise the MDS tables. */ -static void initialise_mds_tables() - { - int i; - Twofish_UInt32 q,qef,q5b; /* Temporary variables. */ - - /* Loop over all 8-bit input values */ - for( i=0; i<256; i++ ) - { - /* - * To save some work during the key expansion we include the last - * of the q-box layers from the h() function in these MDS tables. - */ - - /* We first do the inputs that are mapped through the q0 table. */ - q = q_table[0][i]; - /* - * Here we divide by x, note the table to get 0xb4 only if the - * lsbit is set. - * This sets qef = (1/x)*q in the finite field - */ - qef = (q >> 1) ^ mds_poly_divx_const[ q & 1 ]; - /* - * Divide by x again, and add q to get (1+1/x^2)*q. - * Note that (1+1/x^2) = 5B in the field, and addition in the field - * is exclusive or on the bits. - */ - q5b = (qef >> 1) ^ mds_poly_divx_const[ qef & 1 ] ^ q; - /* - * Add q5b to qef to set qef = (1+1/x+1/x^2)*q. - * Again, (1+1/x+1/x^2) = EF in the field. - */ - qef ^= q5b; - - /* - * Now that we have q5b = 5B * q and qef = EF * q - * we can fill two of the entries in the MDS matrix table. - * See the Twofish specifications for the order of the constants. - */ - MDS_table[1][i] = (q <<24) | (q5b<<16) | (qef<<8) | qef; - MDS_table[3][i] = (q5b<<24) | (qef<<16) | (q <<8) | q5b; - - /* Now we do it all again for the two columns that have a q1 box. */ - q = q_table[1][i]; - qef = (q >> 1) ^ mds_poly_divx_const[ q & 1 ]; - q5b = (qef >> 1) ^ mds_poly_divx_const[ qef & 1 ] ^ q; - qef ^= q5b; - - /* The other two columns use the coefficient in a different order. */ - MDS_table[0][i] = (qef<<24) | (qef<<16) | (q5b<<8) | q ; - MDS_table[2][i] = (qef<<24) | (q <<16) | (qef<<8) | q5b; - } - } - - -/* - * The h() function is the heart of the Twofish cipher. - * It is a complicated sequence of q-box lookups, key material xors, - * and finally the MDS matrix. - * We use lots of macros to make this reasonably fast. - */ - -/* First a shorthand for the two q-tables */ -#define q0 q_table[0] -#define q1 q_table[1] - -/* - * Each macro computes one column of the h for either 2, 3, or 4 stages. - * As there are 4 columns, we have 12 macros in all. - * - * The key bytes are stored in the Byte array L at offset - * 0,1,2,3, 8,9,10,11, [16,17,18,19, [24,25,26,27]] as this is the - * order we get the bytes from the user. If you look at the Twofish - * specs, you'll see that h() is applied to the even key words or the - * odd key words. The bytes of the even words appear in this spacing, - * and those of the odd key words too. - * - * These macros are the only place where the q-boxes and the MDS table - * are used. - */ -#define H02( y, L ) MDS_table[0][q0[q0[y]^L[ 8]]^L[0]] -#define H12( y, L ) MDS_table[1][q0[q1[y]^L[ 9]]^L[1]] -#define H22( y, L ) MDS_table[2][q1[q0[y]^L[10]]^L[2]] -#define H32( y, L ) MDS_table[3][q1[q1[y]^L[11]]^L[3]] -#define H03( y, L ) H02( q1[y]^L[16], L ) -#define H13( y, L ) H12( q1[y]^L[17], L ) -#define H23( y, L ) H22( q0[y]^L[18], L ) -#define H33( y, L ) H32( q0[y]^L[19], L ) -#define H04( y, L ) H03( q1[y]^L[24], L ) -#define H14( y, L ) H13( q0[y]^L[25], L ) -#define H24( y, L ) H23( q0[y]^L[26], L ) -#define H34( y, L ) H33( q1[y]^L[27], L ) - -/* - * Now we can define the h() function given an array of key bytes. - * This function is only used in the key schedule, and not to pre-compute - * the keyed S-boxes. - * - * In the key schedule, the input is always of the form k*(1+2^8+2^16+2^24) - * so we only provide k as an argument. - * - * Arguments: - * k input to the h() function. - * L pointer to array of key bytes at - * offsets 0,1,2,3, ... 8,9,10,11, [16,17,18,19, [24,25,26,27]] - * kCycles # key cycles, 2, 3, or 4. - */ -static Twofish_UInt32 h( int k, Twofish_Byte L[], int kCycles ) - { - switch( kCycles ) { - /* We code all 3 cases separately for speed reasons. */ - case 2: - return H02(k,L) ^ H12(k,L) ^ H22(k,L) ^ H32(k,L); - case 3: - return H03(k,L) ^ H13(k,L) ^ H23(k,L) ^ H33(k,L); - case 4: - return H04(k,L) ^ H14(k,L) ^ H24(k,L) ^ H34(k,L); - default: - /* This is always a coding error, which is fatal. */ - Twofish_fatal( "Twofish h(): Illegal argument", ERR_ILL_ARG ); - return ERR_ILL_ARG; - } - } - - -/* - * Pre-compute the keyed S-boxes. - * Fill the pre-computed S-box array in the expanded key structure. - * Each pre-computed S-box maps 8 bits to 32 bits. - * - * The S argument contains half the number of bytes of the full key, but is - * derived from the full key. (See Twofish specifications for details.) - * S has the weird byte input order used by the Hxx macros. - * - * This function takes most of the time of a key expansion. - * - * Arguments: - * S pointer to array of 8*kCycles Bytes containing the S vector. - * kCycles number of key words, must be in the set {2,3,4} - * xkey pointer to Twofish_key structure that will contain the S-boxes. - */ -static int fill_keyed_sboxes( Twofish_Byte S[], int kCycles, Twofish_key * xkey ) - { - int i; - switch( kCycles ) { - /* We code all 3 cases separately for speed reasons. */ - case 2: - for( i=0; i<256; i++ ) - { - xkey->s[0][i]= H02( i, S ); - xkey->s[1][i]= H12( i, S ); - xkey->s[2][i]= H22( i, S ); - xkey->s[3][i]= H32( i, S ); - } - break; - case 3: - for( i=0; i<256; i++ ) - { - xkey->s[0][i]= H03( i, S ); - xkey->s[1][i]= H13( i, S ); - xkey->s[2][i]= H23( i, S ); - xkey->s[3][i]= H33( i, S ); - } - break; - case 4: - for( i=0; i<256; i++ ) - { - xkey->s[0][i]= H04( i, S ); - xkey->s[1][i]= H14( i, S ); - xkey->s[2][i]= H24( i, S ); - xkey->s[3][i]= H34( i, S ); - } - break; - default: - /* This is always a coding error, which is fatal. */ - Twofish_fatal( "Twofish fill_keyed_sboxes(): Illegal argument", ERR_ILL_ARG ); - } - return SUCCESS; - } - - -/* A flag to keep track of whether we have been initialised or not. */ -static int Twofish_initialised = 0; - -/* - * Initialise the Twofish implementation. - * This function must be called before any other function in the - * Twofish implementation is called. - * This routine also does some sanity checks, to make sure that - * all the macros behave, and it tests the whole cipher. - */ -int Twofish_initialise() - { - int ret; - /* First test the various platform-specific definitions. */ - if ((ret = test_platform()) < 0) - return ret; - - /* We can now generate our tables, in the right order of course. */ - initialise_q_boxes(); - initialise_mds_tables(); - - /* We're finished with the initialisation itself. */ - Twofish_initialised = 1; - - /* - * And run some tests on the whole cipher. - * Yes, you need to do this every time you start your program. - * It is called assurance; you have to be certain that your program - * still works properly. - */ - return self_test(); - } - - -/* - * The Twofish key schedule uses an Reed-Solomon code matrix multiply. - * Just like the MDS matrix, the RS-matrix is designed to be easy - * to implement. Details are below in the code. - * - * These constants make it easy to compute in the finite field used - * for the RS code. - * - * We use Bytes for the RS computation, but these are automatically - * widened to unsigned integers in the expressions. Having unsigned - * ints in these tables therefore provides the fastest access. - */ -static unsigned int rs_poly_const[] = {0, 0x14d}; -static unsigned int rs_poly_div_const[] = {0, 0xa6 }; - -/* - * memset_volatile is a volatile pointer to the memset function. - * You can call (*memset_volatile)(buf, val, len) or even - * memset_volatile(buf, val, len) just as you would call - * memset(buf, val, len), but the use of a volatile pointer - * guarantees that the compiler will not optimise the call away. - */ -static void * (*volatile memset_volatile)(void *, int, size_t) = memset; - -/* - * Prepare a key for use in encryption and decryption. - * Like most block ciphers, Twofish allows the key schedule - * to be pre-computed given only the key. - * Twofish has a fairly 'heavy' key schedule that takes a lot of time - * to compute. The main work is pre-computing the S-boxes used in the - * encryption and decryption. We feel that this makes the cipher much - * harder to attack. The attacker doesn't even know what the S-boxes - * contain without including the entire key schedule in the analysis. - * - * Unlike most Twofish implementations, this one allows any key size from - * 0 to 32 bytes. Odd key sizes are defined for Twofish (see the - * specifications); the key is simply padded with zeroes to the next real - * key size of 16, 24, or 32 bytes. - * Each odd-sized key is thus equivalent to a single normal-sized key. - * - * Arguments: - * key array of key bytes - * key_len number of bytes in the key, must be in the range 0,...,32. - * xkey Pointer to an Twofish_key structure that will be filled - * with the internal form of the cipher key. - */ -int Twofish_prepare_key( Twofish_Byte key[], int key_len, Twofish_key * xkey ) - { - /* We use a single array to store all key material in, - * to simplify the wiping of the key material at the end. - * The first 32 bytes contain the actual (padded) cipher key. - * The next 32 bytes contain the S-vector in its weird format, - * and we have 4 bytes of overrun necessary for the RS-reduction. - */ - Twofish_Byte K[32+32+4]; - - int kCycles; /* # key cycles, 2,3, or 4. */ - - int i; - Twofish_UInt32 A, B; /* Used to compute the round keys. */ - - Twofish_Byte * kptr; /* Three pointers for the RS computation. */ - Twofish_Byte * sptr; - Twofish_Byte * t; - - Twofish_Byte b,bx,bxx; /* Some more temporaries for the RS computation. */ - - /* Check that the Twofish implementation was initialised. */ - if( Twofish_initialised == 0 ) - { - /* - * You didn't call Twofish_initialise before calling this routine. - * This is a programming error, and therefore we call the fatal - * routine. - * - * I could of course call the initialisation routine here, - * but there are a few reasons why I don't. First of all, the - * self-tests have to be done at startup. It is no good to inform - * the user that the cipher implementation fails when he wants to - * write his data to disk in encrypted form. You have to warn him - * before he spends time typing his data. Second, the initialisation - * and self test are much slower than a single key expansion. - * Calling the initialisation here makes the performance of the - * cipher unpredictable. This can lead to really weird problems - * if you use the cipher for a real-time task. Suddenly it fails - * once in a while the first time you try to use it. Things like - * that are almost impossible to debug. - */ - /* Twofish_fatal( "Twofish implementation was not initialised.", ERR_INIT ); */ - - /* - * There is always a danger that the Twofish_fatal routine returns, - * in spite of the specifications that it should not. - * (A good programming rule: don't trust the rest of the code.) - * This would be disasterous. If the q-tables and MDS-tables have - * not been initialised, they are probably still filled with zeroes. - * Suppose the MDS-tables are all zero. The key expansion would then - * generate all-zero round keys, and all-zero s-boxes. The danger - * is that nobody would notice as the encry - * mangles the input, and the decryption still 'decrypts' it, - * but now in a completely key-independent manner. - * To stop such security disasters, we use blunt force. - * If your program hangs here: fix the fatal routine! - */ - for(;;); /* Infinite loop, which beats being insecure. */ - } - - /* Check for valid key length. */ - if( key_len < 0 || key_len > 32 ) - { - /* - * This can only happen if a programmer didn't read the limitations - * on the key size. - */ - Twofish_fatal( "Twofish_prepare_key: illegal key length", ERR_KEY_LEN ); - /* - * A return statement just in case the fatal macro returns. - * The rest of the code assumes that key_len is in range, and would - * buffer-overflow if it wasn't. - * - * Why do we still use a programming language that has problems like - * buffer overflows, when these problems were solved in 1960 with - * the development of Algol? Have we not leared anything? - */ - return ERR_KEY_LEN; - } - - /* Pad the key with zeroes to the next suitable key length. */ - memcpy( K, key, key_len ); - memset( K+key_len, 0, sizeof(K)-key_len ); - - /* - * Compute kCycles: the number of key cycles used in the cipher. - * 2 for 128-bit keys, 3 for 192-bit keys, and 4 for 256-bit keys. - */ - kCycles = (key_len + 7) >> 3; - /* Handle the special case of very short keys: minimum 2 cycles. */ - if( kCycles < 2 ) - { - kCycles = 2; - } - - /* - * From now on we just pretend to have 8*kCycles bytes of - * key material in K. This handles all the key size cases. - */ - - /* - * We first compute the 40 expanded key words, - * formulas straight from the Twofish specifications. - */ - for( i=0; i<40; i+=2 ) - { - /* - * Due to the byte spacing expected by the h() function - * we can pick the bytes directly from the key K. - * As we use bytes, we never have the little/big endian - * problem. - * - * Note that we apply the rotation function only to simple - * variables, as the rotation macro might evaluate its argument - * more than once. - */ - A = h( i , K , kCycles ); - B = h( i+1, K+4, kCycles ); - B = ROL32( B, 8 ); - - /* Compute and store the round keys. */ - A += B; - B += A; - xkey->K[i] = A; - xkey->K[i+1] = ROL32( B, 9 ); - } - - /* Wipe variables that contained key material. */ - A=B=0; - - /* - * And now the dreaded RS multiplication that few seem to understand. - * The RS matrix is not random, and is specially designed to compute the - * RS matrix multiplication in a simple way. - * - * We work in the field GF(2)[x]/x^8+x^6+x^3+x^2+1. Note that this is a - * different field than used for the MDS matrix. - * (At least, it is a different representation because all GF(2^8) - * representations are equivalent in some form.) - * - * We take 8 consecutive bytes of the key and interpret them as - * a polynomial k_0 + k_1 y + k_2 y^2 + ... + k_7 y^7 where - * the k_i bytes are the key bytes and are elements of the finite field. - * We multiply this polynomial by y^4 and reduce it modulo - * y^4 + (x + 1/x)y^3 + (x)y^2 + (x + 1/x)y + 1. - * using straightforward polynomial modulo reduction. - * The coefficients of the result are the result of the RS - * matrix multiplication. When we wrote the Twofish specification, - * the original RS definition used the polynomials, - * but that requires much more mathematical knowledge. - * We were already using matrix multiplication in a finite field for - * the MDS matrix, so I re-wrote the RS operation as a matrix - * multiplication to reduce the difficulty of understanding it. - * Some implementors have not picked up on this simpler method of - * computing the RS operation, even though it is mentioned in the - * specifications. - * - * It is possible to perform these computations faster by using 32-bit - * word operations, but that is not portable and this is not a speed- - * critical area. - * - * We explained the 1/x computation when we did the MDS matrix. - * - * The S vector is stored in K[32..64]. - * The S vector has to be reversed, so we loop cross-wise. - * - * Note the weird byte spacing of the S-vector, to match the even - * or odd key words arrays. See the discussion at the Hxx macros for - * details. - */ - kptr = K + 8*kCycles; /* Start at end of key */ - sptr = K + 32; /* Start at start of S */ - - /* Loop over all key material */ - while( kptr > K ) - { - kptr -= 8; - /* - * Initialise the polynimial in sptr[0..12] - * The first four coefficients are 0 as we have to multiply by y^4. - * The next 8 coefficients are from the key material. - */ - memset( sptr, 0, 4 ); - memcpy( sptr+4, kptr, 8 ); - - /* - * The 12 bytes starting at sptr are now the coefficients of - * the polynomial we need to reduce. - */ - - /* Loop over the polynomial coefficients from high to low */ - t = sptr+11; - /* Keep looping until polynomial is degree 3; */ - while( t > sptr+3 ) - { - /* Pick up the highest coefficient of the poly. */ - b = *t; - - /* - * Compute x and (x+1/x) times this coefficient. - * See the MDS matrix implementation for a discussion of - * multiplication by x and 1/x. We just use different - * constants here as we are in a - * different finite field representation. - * - * These two statements set - * bx = (x) * b - * bxx= (x + 1/x) * b - */ - bx = (Twofish_Byte)((b<<1) ^ rs_poly_const[ b>>7 ]); - bxx= (Twofish_Byte)((b>>1) ^ rs_poly_div_const[ b&1 ] ^ bx); - - /* - * Subtract suitable multiple of - * y^4 + (x + 1/x)y^3 + (x)y^2 + (x + 1/x)y + 1 - * from the polynomial, except that we don't bother - * updating t[0] as it will become zero anyway. - */ - t[-1] ^= bxx; - t[-2] ^= bx; - t[-3] ^= bxx; - t[-4] ^= b; - - /* Go to the next coefficient. */ - t--; - } - - /* Go to next S-vector word, obeying the weird spacing rules. */ - sptr += 8; - } - - /* Wipe variables that contained key material. */ - b = bx = bxx = 0; - - /* And finally, we can compute the key-dependent S-boxes. */ - fill_keyed_sboxes( &K[32], kCycles, xkey ); - - /* Wipe array that contained key material. */ - (*memset_volatile)( K, 0, sizeof( K ) ); - return SUCCESS; - } - - -/* - * We can now start on the actual encryption and decryption code. - * As these are often speed-critical we will use a lot of macros. - */ - -/* - * The g() function is the heart of the round function. - * We have two versions of the g() function, one without an input - * rotation and one with. - * The pre-computed S-boxes make this pretty simple. - */ -#define g0(X,xkey) \ - (xkey->s[0][b0(X)]^xkey->s[1][b1(X)]^xkey->s[2][b2(X)]^xkey->s[3][b3(X)]) - -#define g1(X,xkey) \ - (xkey->s[0][b3(X)]^xkey->s[1][b0(X)]^xkey->s[2][b1(X)]^xkey->s[3][b2(X)]) - -/* - * A single round of Twofish. The A,B,C,D are the four state variables, - * T0 and T1 are temporaries, xkey is the expanded key, and r the - * round number. - * - * Note that this macro does not implement the swap at the end of the round. - */ -#define ENCRYPT_RND( A,B,C,D, T0, T1, xkey, r ) \ - T0 = g0(A,xkey); T1 = g1(B,xkey);\ - C ^= T0+T1+xkey->K[8+2*(r)]; C = ROR32(C,1);\ - D = ROL32(D,1); D ^= T0+2*T1+xkey->K[8+2*(r)+1] - -/* - * Encrypt a single cycle, consisting of two rounds. - * This avoids the swapping of the two halves. - * Parameter r is now the cycle number. - */ -#define ENCRYPT_CYCLE( A, B, C, D, T0, T1, xkey, r ) \ - ENCRYPT_RND( A,B,C,D,T0,T1,xkey,2*(r) );\ - ENCRYPT_RND( C,D,A,B,T0,T1,xkey,2*(r)+1 ) - -/* Full 16-round encryption */ -#define ENCRYPT( A,B,C,D,T0,T1,xkey ) \ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 0 );\ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 1 );\ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 2 );\ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 3 );\ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 4 );\ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 5 );\ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 6 );\ - ENCRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 7 ) - -/* - * A single round of Twofish for decryption. It differs from - * ENCRYTP_RND only because of the 1-bit rotations. - */ -#define DECRYPT_RND( A,B,C,D, T0, T1, xkey, r ) \ - T0 = g0(A,xkey); T1 = g1(B,xkey);\ - C = ROL32(C,1); C ^= T0+T1+xkey->K[8+2*(r)];\ - D ^= T0+2*T1+xkey->K[8+2*(r)+1]; D = ROR32(D,1) - -/* - * Decrypt a single cycle, consisting of two rounds. - * This avoids the swapping of the two halves. - * Parameter r is now the cycle number. - */ -#define DECRYPT_CYCLE( A, B, C, D, T0, T1, xkey, r ) \ - DECRYPT_RND( A,B,C,D,T0,T1,xkey,2*(r)+1 );\ - DECRYPT_RND( C,D,A,B,T0,T1,xkey,2*(r) ) - -/* Full 16-round decryption. */ -#define DECRYPT( A,B,C,D,T0,T1, xkey ) \ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 7 );\ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 6 );\ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 5 );\ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 4 );\ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 3 );\ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 2 );\ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 1 );\ - DECRYPT_CYCLE( A,B,C,D,T0,T1,xkey, 0 ) - -/* - * A macro to read the state from the plaintext and do the initial key xors. - * The koff argument allows us to use the same macro - * for the decryption which uses different key words at the start. - */ -#define GET_INPUT( src, A,B,C,D, xkey, koff ) \ - A = GET32(src )^xkey->K[ koff]; B = GET32(src+ 4)^xkey->K[1+koff]; \ - C = GET32(src+ 8)^xkey->K[2+koff]; D = GET32(src+12)^xkey->K[3+koff] - -/* - * Similar macro to put the ciphertext in the output buffer. - * We xor the keys into the state variables before we use the PUT32 - * macro as the macro might use its argument multiple times. - */ -#define PUT_OUTPUT( A,B,C,D, dst, xkey, koff ) \ - A ^= xkey->K[ koff]; B ^= xkey->K[1+koff]; \ - C ^= xkey->K[2+koff]; D ^= xkey->K[3+koff]; \ - PUT32( A, dst ); PUT32( B, dst+ 4 ); \ - PUT32( C, dst+8 ); PUT32( D, dst+12 ) - - -/* - * Twofish block encryption - * - * Arguments: - * xkey expanded key array - * p 16 bytes of plaintext - * c 16 bytes in which to store the ciphertext - */ -void Twofish_encrypt( Twofish_key * xkey, Twofish_Byte p[16], Twofish_Byte c[16]) - { - Twofish_UInt32 A,B,C,D,T0,T1; /* Working variables */ - - /* Get the four plaintext words xorred with the key */ - GET_INPUT( p, A,B,C,D, xkey, 0 ); - - /* Do 8 cycles (= 16 rounds) */ - ENCRYPT( A,B,C,D,T0,T1,xkey ); - - /* Store them with the final swap and the output whitening. */ - PUT_OUTPUT( C,D,A,B, c, xkey, 4 ); - } - - -/* - * Twofish block decryption. - * - * Arguments: - * xkey expanded key array - * p 16 bytes of plaintext - * c 16 bytes in which to store the ciphertext - */ -void Twofish_decrypt( Twofish_key * xkey, Twofish_Byte c[16], Twofish_Byte p[16]) - { - Twofish_UInt32 A,B,C,D,T0,T1; /* Working variables */ - - /* Get the four plaintext words xorred with the key */ - GET_INPUT( c, A,B,C,D, xkey, 4 ); - - /* Do 8 cycles (= 16 rounds) */ - DECRYPT( A,B,C,D,T0,T1,xkey ); - - /* Store them with the final swap and the output whitening. */ - PUT_OUTPUT( C,D,A,B, p, xkey, 0 ); - } - -/* - * Using the macros it is easy to make special routines for - * CBC mode, CTR mode etc. The only thing you might want to - * add is a XOR_PUT_OUTPUT which xors the outputs into the - * destinationa instead of overwriting the data. This requires - * a XOR_PUT32 macro as well, but that should all be trivial. - * - * I thought about including routines for the separate cipher - * modes here, but it is unclear which modes should be included, - * and each encryption or decryption routine takes up a lot of code space. - * Also, I don't have any test vectors for any cipher modes - * with Twofish. - */ - - diff --git a/libs/libks/crypt/twofish.h b/libs/libks/crypt/twofish.h deleted file mode 100755 index 21d7e96341..0000000000 --- a/libs/libks/crypt/twofish.h +++ /dev/null @@ -1,265 +0,0 @@ -/* - * Fast, portable, and easy-to-use Twofish implementation, - * Version 0.3. - * Copyright (c) 2002 by Niels Ferguson. - * - * See the twofish.c file for the details of the how and why of this code. - * - * The author hereby grants a perpetual license to everybody to - * use this code for any purpose as long as the copyright message is included - * in the source code of this or any derived work. - */ - - -/* - * PLATFORM FIXES - * ============== - * - * The following definitions have to be fixed for each particular platform - * you work on. If you have a multi-platform program, you no doubt have - * portable definitions that you can substitute here without changing - * the rest of the code. - * - * The defaults provided here should work on most PC compilers. - */ - -#ifndef TWOFISH_H -#define TWOFISH_H - -#ifdef __cplusplus -extern "C" -{ -#endif - -/** - * @file twofish.h - * @brief Function that provide basic Twofish crypto support - * - * @ingroup GNU_ZRTP - * @{ - */ - -/** - * A Twofish_Byte must be an unsigned 8-bit integer. - * - * It must also be the elementary data size of your C platform, - * i.e. sizeof( Twofish_Byte ) == 1. - */ -typedef unsigned char Twofish_Byte; - -/** - * A Twofish_UInt32 must be an unsigned integer of at least 32 bits. - * - * This type is used only internally in the implementation, so ideally it - * would not appear in the header file, but it is used inside the - * Twofish_key structure which means it has to be included here. - */ -typedef unsigned int Twofish_UInt32; - - -/* - * END OF PLATFORM FIXES - * ===================== - * - * You should not have to touch the rest of this file, but the code - * in twofish.c has a few things you need to fix too. - */ - -/** - * Return codes - */ -#define SUCCESS 1 -#define ERR_UINT32 -2 -#define ERR_BYTE -3 -#define ERR_GET32 -4 -#define ERR_PUT32 -5 -#define ERR_ROLR -6 -#define ERR_BSWAP -7 -#define ERR_SELECTB -8 -#define ERR_TEST_ENC -9 -#define ERR_TEST_DEC -10 -#define ERR_SEQ_ENC -11 -#define ERR_SEQ_DEC -12 -#define ERR_ODD_KEY -13 -#define ERR_INIT -14 -#define ERR_KEY_LEN -15 -#define ERR_ILL_ARG -16 - - -/** - * Structure that contains a prepared Twofish key. - * - * A cipher key is used in two stages. In the first stage it is converted - * form the original form to an internal representation. - * This internal form is then used to encrypt and decrypt data. - * This structure contains the internal form. It is rather large: 4256 bytes - * on a platform with 32-bit unsigned values. - * - * Treat this as an opague structure, and don't try to manipulate the - * elements in it. I wish I could hide the inside of the structure, - * but C doesn't allow that. - */ -typedef - struct - { - Twofish_UInt32 s[4][256]; /* pre-computed S-boxes */ - Twofish_UInt32 K[40]; /* Round key words */ - } - Twofish_key; - - -/** - * Initialise and test the Twofish implementation. - * - * This function MUST be called before any other function in the - * Twofish implementation is called. - * It only needs to be called once. - * - * Apart from initialising the implementation it performs a self test. - * If the Twofish_fatal function is not called, the code passed the test. - * (See the twofish.c file for details on the Twofish_fatal function.) - * - * @returns a negative number if an error happend, +1 otherwise - */ -extern int Twofish_initialise(); - - -/** - * Convert a cipher key to the internal form used for - * encryption and decryption. - * - * The cipher key is an array of bytes; the Twofish_Byte type is - * defined above to a type suitable on your platform. - * - * Any key must be converted to an internal form in the Twofisk_key structure - * before it can be used. - * The encryption and decryption functions only work with the internal form. - * The conversion to internal form need only be done once for each key value. - * - * Be sure to wipe all key storage, including the Twofish_key structure, - * once you are done with the key data. - * A simple memset( TwofishKey, 0, sizeof( TwofishKey ) ) will do just fine. - * - * Unlike most implementations, this one allows any key size from 0 bytes - * to 32 bytes. According to the Twofish specifications, - * irregular key sizes are handled by padding the key with zeroes at the end - * until the key size is 16, 24, or 32 bytes, whichever - * comes first. Note that each key of irregular size is equivalent to exactly - * one key of 16, 24, or 32 bytes. - * - * WARNING: Short keys have low entropy, and result in low security. - * Anything less than 8 bytes is utterly insecure. For good security - * use at least 16 bytes. I prefer to use 32-byte keys to prevent - * any collision attacks on the key. - * - * The key length argument key_len must be in the proper range. - * If key_len is not in the range 0,...,32 this routine attempts to generate - * a fatal error (depending on the code environment), - * and at best (or worst) returns without having done anything. - * - * @param key Array of key bytes - * @param key_len Number of key bytes, must be in the range 0,1,...,32. - * @param xkey Pointer to an Twofish_key structure that will be filled - * with the internal form of the cipher key. - * @returns a negative number if an error happend, +1 otherwise - */ -extern int Twofish_prepare_key( - Twofish_Byte key[], - int key_len, - Twofish_key * xkey - ); - - -/** - * Encrypt a single block of data. - * - * This function encrypts a single block of 16 bytes of data. - * If you want to encrypt a larger or variable-length message, - * you will have to use a cipher mode, such as CBC or CTR. - * These are outside the scope of this implementation. - * - * The xkey structure is not modified by this routine, and can be - * used for further encryption and decryption operations. - * - * @param xkey pointer to Twofish_key, internal form of the key - * produces by Twofish_prepare_key() - * @param p Plaintext to be encrypted - * @param c Place to store the ciphertext - */ -extern void Twofish_encrypt( - Twofish_key * xkey, - Twofish_Byte p[16], - Twofish_Byte c[16] - ); - - -/** - * Decrypt a single block of data. - * - * This function decrypts a single block of 16 bytes of data. - * If you want to decrypt a larger or variable-length message, - * you will have to use a cipher mode, such as CBC or CTR. - * These are outside the scope of this implementation. - * - * The xkey structure is not modified by this routine, and can be - * used for further encryption and decryption operations. - * - * @param xkey pointer to Twofish_key, internal form of the key - * produces by Twofish_prepare_key() - * @param c Ciphertext to be decrypted - * @param p Place to store the plaintext - */ -extern void Twofish_decrypt( - Twofish_key * xkey, - Twofish_Byte c[16], - Twofish_Byte p[16] - ); - - -/** - * Encrypt data in CFB mode. - * - * This function encrypts data in CFB mode. - * - * The key structure is not modified by this routine, and can be - * used for further encryption and decryption operations. - * - * @param keyCtx pointer to Twofish_key, internal form of the key - * produced by Twofish_prepare_key() - * @param in Plaintext to be encrypted - * @param out Place to store the ciphertext - * @param len number of bytes to encrypt. - * @param ivec initialization vector for this CFB mode encryption. - * @param num pointer to integer that holds number of available crypto bytes. - */ -void Twofish_cfb128_encrypt(Twofish_key* keyCtx, Twofish_Byte* in, - Twofish_Byte* out, size_t len, - Twofish_Byte* ivec, int *num); - -/** - * Decrypt data in CFB mode. - * - * This function decrypts data in CFB. - * - * The key structure is not modified by this routine, and can be - * used for further encryption and decryption operations. - * - * @param keyCtx pointer to Twofish_key, internal form of the key - * produced by Twofish_prepare_key() - * @param in Ciphertext to be decrypted - * @param out Place to store the plaintext - * @param len number of bytes to decrypt. - * @param ivec initialization vector for this CFB mode encryption. - * @param num pointer to integer that holds number of available crypto bytes. - */ -void Twofish_cfb128_decrypt(Twofish_key* keyCtx, Twofish_Byte* in, - Twofish_Byte* out, size_t len, - Twofish_Byte* ivec, int *num); -/** - * @} - */ -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/libks/crypt/twofish_cfb.c b/libs/libks/crypt/twofish_cfb.c deleted file mode 100755 index 8ade853539..0000000000 --- a/libs/libks/crypt/twofish_cfb.c +++ /dev/null @@ -1,98 +0,0 @@ -#include -#include - -#include "twofish.h" - -#ifdef ANDROID -void Two_debugDummy(Twofish_Byte* in, Twofish_Byte* out, Twofish_Byte* ivec); -#endif - -void Twofish_cfb128_encrypt(Twofish_key* keyCtx, Twofish_Byte* in, - Twofish_Byte* out, size_t len, - Twofish_Byte* ivec, int32_t *num) -{ - uint32_t n; - - n = *num; - - do { - while (n && len) { - *(out++) = ivec[n] ^= *(in++); - --len; - n = (n+1) % 16; - } - while (len>=16) { - Twofish_encrypt(keyCtx, ivec, ivec); - for (n=0; n<16; n+=sizeof(size_t)) { - -/* - * Some GCC version(s) of Android's NDK produce code that leads to a crash (SIGBUS). The - * offending line if the line that produces the output by xor'ing the ivec. Somehow the - * compiler/optimizer seems to incorrectly setup the pointers. Adding a call to an - * external function that uses the pointer disabled or modifies this optimzing - * behaviour. This debug functions as such does nothing, it just disables some - * optimization. Don't use a local (static) function - the compiler sees that it does - * nothing and optimizes again :-) . - */ -#ifdef ANDROID - Two_debugDummy(in, out, ivec); -#endif - *(size_t*)(out+n) = *(size_t*)(ivec+n) ^= *(size_t*)(in+n);; - } - len -= 16; - out += 16; - in += 16; - } - n = 0; - if (len) { - Twofish_encrypt(keyCtx, ivec, ivec); - while (len--) { - out[n] = ivec[n] ^= in[n]; - ++n; - } - } - *num = n; - return; - } while (0); -} - - -void Twofish_cfb128_decrypt(Twofish_key* keyCtx, Twofish_Byte* in, - Twofish_Byte* out, size_t len, - Twofish_Byte* ivec, int32_t *num) -{ - uint32_t n; - - n = *num; - - do { - while (n && len) { - unsigned char c; - *(out++) = ivec[n] ^ (c = *(in++)); ivec[n] = c; - --len; - n = (n+1) % 16; - } - while (len>=16) { - Twofish_encrypt(keyCtx, ivec, ivec); - for (n=0; n<16; n+=sizeof(size_t)) { - size_t t = *(size_t*)(in+n); - *(size_t*)(out+n) = *(size_t*)(ivec+n) ^ t; - *(size_t*)(ivec+n) = t; - } - len -= 16; - out += 16; - in += 16; - } - n = 0; - if (len) { - Twofish_encrypt(keyCtx, ivec, ivec); - while (len--) { - unsigned char c; - out[n] = ivec[n] ^ (c = in[n]); ivec[n] = c; - ++n; - } - } - *num = n; - return; - } while (0); -} diff --git a/libs/libks/libks.pc.in b/libs/libks/libks.pc.in deleted file mode 100644 index 6d53390d4f..0000000000 --- a/libs/libks/libks.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ -libdir=@libdir@ -includedir=@includedir@ - -Name: @PACKAGE_NAME@ -Version: @PACKAGE_VERSION@ -Description: A cross platform kitchen sink library. - -Cflags: -I${includedir} -Libs: -L${libdir} -lks diff --git a/libs/libks/libks.props b/libs/libks/libks.props deleted file mode 100644 index 110a0afa2c..0000000000 --- a/libs/libks/libks.props +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - - - UNICODE;SIMCLIST_NO_DUMPRESTORE;_CRT_SECURE_NO_WARNINGS;KS_EXPORTS;%(PreprocessorDefinitions) - $(BaseDir)libs\libks\src\include;$(BaseDir)libs\libks\src\win\sys;$(BaseDir)libs\libks\src\win;%(AdditionalIncludeDirectories) - 4711;4574;4100;4127;4668;4255;4706;4710;4820 - - - Rpcrt4.lib;Winmm.lib;%(AdditionalDependencies) - - - - \ No newline at end of file diff --git a/libs/libks/libks.sln b/libs/libks/libks.sln deleted file mode 100644 index bafb87e2bb..0000000000 --- a/libs/libks/libks.sln +++ /dev/null @@ -1,168 +0,0 @@ - -Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 -MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libks", "libks.vcxproj", "{70D178D8-1100-4152-86C0-809A91CFF832}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testpools", "test\testpools.vcxproj", "{5825A3B2-31A0-475A-AF32-44FB0D8B52D4}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testthreadmutex", "test\testthreadmutex.vcxproj", "{AE572500-7266-4692-ACA4-5E37B7B4409A}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testhash", "test\testhash.vcxproj", "{43724CF4-FCE1-44FE-AB36-C86E3979B350}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testq", "test\testq.vcxproj", "{3F8E0DF3-F402-40E0-8D78-44A094625D25}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testsock", "test\testsock.vcxproj", "{5DC38E2B-0512-4140-8A1B-59952A5DC9CB}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testtime", "test\testtime.vcxproj", "{B74812A1-C67D-4568-AF84-26CE2004D8BF}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testwebsock", "test\testwebsock.vcxproj", "{90D1C15C-59B0-470F-B18A-DA355948C736}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testacl", "test\testacl.vcxproj", "{1E6DE729-F4D4-4455-B64C-73B31C17E12C}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_thread_pools", "test\test_thread_pools.vcxproj", "{8AFFECE6-2A0B-4D44-990C-6D3DD832A250}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Download OPENSSL", "..\win32\Download OPENSSL.2015.vcxproj", "{D578E676-7EC8-4548-BD8B-845C635F14AD}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "libeay32", "..\win32\openssl\libeay32.2015.vcxproj", "{D331904D-A00A-4694-A5A3-FCFF64AB5DBE}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ssleay32", "..\win32\openssl\ssleay32.2015.vcxproj", "{B4B62169-5AD4-4559-8707-3D933AC5DB39}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testrealloc", "test\testrealloc.vcxproj", "{22BCE97F-2477-427D-83FE-74851DDBC57E}" -EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "testpolling", "test\testpolling.vcxproj", "{699A44BF-D03D-469F-83B2-C52C0B4B95BD}" -EndProject -Global - GlobalSection(SolutionConfigurationPlatforms) = preSolution - Debug|x64 = Debug|x64 - Debug|x86 = Debug|x86 - Release|x64 = Release|x64 - Release|x86 = Release|x86 - EndGlobalSection - GlobalSection(ProjectConfigurationPlatforms) = postSolution - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x64.ActiveCfg = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x64.Build.0 = Debug|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x86.ActiveCfg = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Debug|x86.Build.0 = Debug|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x64.ActiveCfg = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x64.Build.0 = Release|x64 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x86.ActiveCfg = Release|Win32 - {70D178D8-1100-4152-86C0-809A91CFF832}.Release|x86.Build.0 = Release|Win32 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x64.ActiveCfg = Debug|x64 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x64.Build.0 = Debug|x64 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x86.ActiveCfg = Debug|Win32 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Debug|x86.Build.0 = Debug|Win32 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x64.ActiveCfg = Release|x64 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x64.Build.0 = Release|x64 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x86.ActiveCfg = Release|Win32 - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4}.Release|x86.Build.0 = Release|Win32 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x64.ActiveCfg = Debug|x64 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x64.Build.0 = Debug|x64 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x86.ActiveCfg = Debug|Win32 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Debug|x86.Build.0 = Debug|Win32 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x64.ActiveCfg = Release|x64 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x64.Build.0 = Release|x64 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x86.ActiveCfg = Release|Win32 - {AE572500-7266-4692-ACA4-5E37B7B4409A}.Release|x86.Build.0 = Release|Win32 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x64.ActiveCfg = Debug|x64 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x64.Build.0 = Debug|x64 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x86.ActiveCfg = Debug|Win32 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Debug|x86.Build.0 = Debug|Win32 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x64.ActiveCfg = Release|x64 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x64.Build.0 = Release|x64 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x86.ActiveCfg = Release|Win32 - {43724CF4-FCE1-44FE-AB36-C86E3979B350}.Release|x86.Build.0 = Release|Win32 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x64.ActiveCfg = Debug|x64 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x64.Build.0 = Debug|x64 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x86.ActiveCfg = Debug|Win32 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Debug|x86.Build.0 = Debug|Win32 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x64.ActiveCfg = Release|x64 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x64.Build.0 = Release|x64 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x86.ActiveCfg = Release|Win32 - {3F8E0DF3-F402-40E0-8D78-44A094625D25}.Release|x86.Build.0 = Release|Win32 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x64.ActiveCfg = Debug|x64 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x64.Build.0 = Debug|x64 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x86.ActiveCfg = Debug|Win32 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Debug|x86.Build.0 = Debug|Win32 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x64.ActiveCfg = Release|x64 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x64.Build.0 = Release|x64 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x86.ActiveCfg = Release|Win32 - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB}.Release|x86.Build.0 = Release|Win32 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x64.ActiveCfg = Debug|x64 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x64.Build.0 = Debug|x64 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x86.ActiveCfg = Debug|Win32 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Debug|x86.Build.0 = Debug|Win32 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x64.ActiveCfg = Release|x64 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x64.Build.0 = Release|x64 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x86.ActiveCfg = Release|Win32 - {B74812A1-C67D-4568-AF84-26CE2004D8BF}.Release|x86.Build.0 = Release|Win32 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Debug|x64.ActiveCfg = Debug|x64 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Debug|x64.Build.0 = Debug|x64 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Debug|x86.ActiveCfg = Debug|Win32 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Debug|x86.Build.0 = Debug|Win32 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Release|x64.ActiveCfg = Release|x64 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Release|x64.Build.0 = Release|x64 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Release|x86.ActiveCfg = Release|Win32 - {90D1C15C-59B0-470F-B18A-DA355948C736}.Release|x86.Build.0 = Release|Win32 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Debug|x64.ActiveCfg = Debug|x64 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Debug|x64.Build.0 = Debug|x64 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Debug|x86.ActiveCfg = Debug|Win32 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Debug|x86.Build.0 = Debug|Win32 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Release|x64.ActiveCfg = Release|x64 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Release|x64.Build.0 = Release|x64 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Release|x86.ActiveCfg = Release|Win32 - {1E6DE729-F4D4-4455-B64C-73B31C17E12C}.Release|x86.Build.0 = Release|Win32 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Debug|x64.ActiveCfg = Debug|x64 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Debug|x64.Build.0 = Debug|x64 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Debug|x86.ActiveCfg = Debug|Win32 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Debug|x86.Build.0 = Debug|Win32 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Release|x64.ActiveCfg = Release|x64 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Release|x64.Build.0 = Release|x64 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Release|x86.ActiveCfg = Release|Win32 - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250}.Release|x86.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.ActiveCfg = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x64.Build.0 = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x86.ActiveCfg = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Debug|x86.Build.0 = Debug|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x64.Build.0 = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x86.ActiveCfg = Release|Win32 - {D578E676-7EC8-4548-BD8B-845C635F14AD}.Release|x86.Build.0 = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.ActiveCfg = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x64.Build.0 = Debug|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x86.ActiveCfg = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Debug|x86.Build.0 = Debug|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.ActiveCfg = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x64.Build.0 = Release|x64 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x86.ActiveCfg = Release|Win32 - {D331904D-A00A-4694-A5A3-FCFF64AB5DBE}.Release|x86.Build.0 = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.ActiveCfg = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x64.Build.0 = Debug|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x86.ActiveCfg = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Debug|x86.Build.0 = Debug|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.ActiveCfg = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x64.Build.0 = Release|x64 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x86.ActiveCfg = Release|Win32 - {B4B62169-5AD4-4559-8707-3D933AC5DB39}.Release|x86.Build.0 = Release|Win32 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Debug|x64.ActiveCfg = Debug|x64 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Debug|x64.Build.0 = Debug|x64 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Debug|x86.ActiveCfg = Debug|Win32 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Debug|x86.Build.0 = Debug|Win32 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Release|x64.ActiveCfg = Release|x64 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Release|x64.Build.0 = Release|x64 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Release|x86.ActiveCfg = Release|Win32 - {22BCE97F-2477-427D-83FE-74851DDBC57E}.Release|x86.Build.0 = Release|Win32 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Debug|x64.ActiveCfg = Debug|x64 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Debug|x64.Build.0 = Debug|x64 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Debug|x86.ActiveCfg = Debug|Win32 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Debug|x86.Build.0 = Debug|Win32 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Release|x64.ActiveCfg = Release|x64 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Release|x64.Build.0 = Release|x64 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Release|x86.ActiveCfg = Release|Win32 - {699A44BF-D03D-469F-83B2-C52C0B4B95BD}.Release|x86.Build.0 = Release|Win32 - EndGlobalSection - GlobalSection(SolutionProperties) = preSolution - HideSolutionNode = FALSE - EndGlobalSection -EndGlobal diff --git a/libs/libks/libks.vcxproj b/libs/libks/libks.vcxproj deleted file mode 100644 index 5a3a3ca7b0..0000000000 --- a/libs/libks/libks.vcxproj +++ /dev/null @@ -1,251 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {70D178D8-1100-4152-86C0-809A91CFF832} - Win32Proj - 8.1 - - - - DynamicLibrary - true - v140 - Unicode - - - DynamicLibrary - false - v140 - Unicode - - - StaticLibrary - true - v140 - Unicode - - - StaticLibrary - false - v140 - Unicode - - - - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(ProjectDir);$(ProjectDir)\crypt;$(IncludePath) - $(LibraryPath) - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset - true - - - - - $(Platform)\$(Configuration)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(ProjectDir);$(ProjectDir)\crypt;$(IncludePath) - $(LibraryPath) - - - $(ProjectDir);$(ProjectDir)\crypt;$(IncludePath) - $(LibraryPath) - C:\Program Files (x86)\Microsoft Visual Studio 14.0\Team Tools\Static Analysis Tools\Rule Sets\NativeRecommendedRules.ruleset - true - - - $(ProjectDir);$(ProjectDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - WIN32;_DEBUG;_WINDOWS;_USRDLL;LIBKS_EXPORTS;CJSON_EXPORT_SYMBOLS;%(PreprocessorDefinitions) - MultiThreadedDebugDLL - EnableAllWarnings - ProgramDatabase - Disabled - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702 - true - false - true - - - MachineX86 - true - Windows - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - WIN32;NDEBUG;_WINDOWS;_USRDLL;LIBKS_EXPORTS;CJSON_EXPORT_SYMBOLS;%(PreprocessorDefinitions) - MultiThreadedDLL - EnableAllWarnings - ProgramDatabase - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702 - true - - - MachineX86 - true - Windows - true - true - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - WIN32;_DEBUG;_WINDOWS;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - EditAndContinue - EnableAllWarnings - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702 - true - false - true - MultiThreadedDebugDLL - - - Windows - Debug - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - - - - - WIN32;NDEBUG;_WINDOWS;KS_DECLARE_STATIC;%(PreprocessorDefinitions) - EnableAllWarnings - true - true - 4711;4574;4100;4127;4668;4255;4706;4710;4820;4090;4702 - true - MultiThreadedDLL - - - Windows - Rpcrt4.lib;Crypt32.lib;%(AdditionalDependencies) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/libks.vcxproj.filters b/libs/libks/libks.vcxproj.filters deleted file mode 100644 index 9e280a5cbc..0000000000 --- a/libs/libks/libks.vcxproj.filters +++ /dev/null @@ -1,207 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hh;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/libs/libks/src/cJSON.c b/libs/libks/src/cJSON.c deleted file mode 100644 index ecde9bfdbc..0000000000 --- a/libs/libks/src/cJSON.c +++ /dev/null @@ -1,2169 +0,0 @@ -/* - Copyright (c) 2009 Dave Gamble - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -/* cJSON */ -/* JSON parser in C. */ - -#include -#include -#include -#include -#include -#include -#include -#include "ks_cJSON.h" - -/* define our own boolean type */ -typedef int cjbool; -#define true ((cjbool)1) -#define false ((cjbool)0) - -static const unsigned char *global_ep = NULL; - -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void) -{ - return (const char*) global_ep; -} - -/* This is a safeguard to prevent copy-pasters from using incompatible C and header files */ -#if (CJSON_VERSION_MAJOR != 1) || (CJSON_VERSION_MINOR != 3) || (CJSON_VERSION_PATCH != 0) - #error cJSON.h and cJSON.c have different versions. Make sure that both have the same. -#endif - -CJSON_PUBLIC(const char*) cJSON_Version(void) -{ - static char version[15]; - sprintf(version, "%i.%i.%i", CJSON_VERSION_MAJOR, CJSON_VERSION_MINOR, CJSON_VERSION_PATCH); - - return version; -} - -/* case insensitive strcmp */ -static int cJSON_strcasecmp(const unsigned char *s1, const unsigned char *s2) -{ - if (!s1) - { - return (s1 == s2) ? 0 : 1; /* both NULL? */ - } - if (!s2) - { - return 1; - } - for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) - { - if (*s1 == '\0') - { - return 0; - } - } - - return tolower(*s1) - tolower(*s2); -} - -static void *glue_malloc(size_t theSize) -{ - return malloc(theSize); -} - -static void glue_free(void *thePtr) -{ - free(thePtr); -} - -static void *glue_realloc(void *pointer, size_t theSize) -{ - return realloc(pointer, theSize); -} - -typedef struct internal_hooks -{ - void *(*allocate)(size_t size); - void (*deallocate)(void *pointer); - void *(*reallocate)(void *pointer, size_t size); -} internal_hooks; - -static internal_hooks global_hooks = { glue_malloc, glue_free, glue_realloc }; - -static unsigned char* cJSON_strdup(const unsigned char* str, const internal_hooks * const hooks) -{ - size_t len = 0; - unsigned char *copy = NULL; - const unsigned char *s = str ? str : (unsigned char *)""; - - len = strlen((const char*)s) + 1; - if (!(copy = (unsigned char*)hooks->allocate(len))) - { - return NULL; - } - memcpy(copy, s, len); - - return copy; -} - -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks) -{ - if (hooks == NULL) - { - /* Reset hooks */ - global_hooks.allocate = malloc; - global_hooks.deallocate = free; - global_hooks.reallocate = realloc; - return; - } - - global_hooks.allocate = malloc; - if (hooks->malloc_fn != NULL) - { - global_hooks.allocate = hooks->malloc_fn; - } - - global_hooks.deallocate = free; - if (hooks->free_fn != NULL) - { - global_hooks.deallocate = hooks->free_fn; - } - - /* use realloc only if both free and malloc are used */ - global_hooks.reallocate = NULL; - if ((global_hooks.allocate == malloc) && (global_hooks.deallocate == free)) - { - global_hooks.reallocate = realloc; - } -} - -/* Internal constructor. */ -static cJSON *cJSON_New_Item(const internal_hooks * const hooks) -{ - cJSON* node = (cJSON*)hooks->allocate(sizeof(cJSON)); - if (node) - { - memset(node, '\0', sizeof(cJSON)); - } - - return node; -} - -/* Delete a cJSON structure. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *c) -{ - cJSON *next = NULL; - while (c) - { - next = c->next; - if (!(c->type & cJSON_IsReference) && c->child) - { - cJSON_Delete(c->child); - } - if (!(c->type & cJSON_IsReference) && c->valuestring) - { - global_hooks.deallocate(c->valuestring); - } - if (!(c->type & cJSON_StringIsConst) && c->string) - { - global_hooks.deallocate(c->string); - } - global_hooks.deallocate(c); - c = next; - } -} - -/* Parse the input text to generate a number, and populate the result into item. */ -static const unsigned char *parse_number(cJSON * const item, const unsigned char * const input) -{ - double number = 0; - unsigned char *after_end = NULL; - - if (input == NULL) - { - return NULL; - } - - number = strtod((const char*)input, (char**)&after_end); - if (input == after_end) - { - return NULL; /* parse_error */ - } - - item->valuedouble = number; - - /* use saturation in case of overflow */ - if (number >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (number <= INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)number; - } - - item->type = cJSON_Number; - - return after_end; -} - -/* don't ask me, but the original cJSON_SetNumberValue returns an integer or double */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number) -{ - if (number >= INT_MAX) - { - object->valueint = INT_MAX; - } - else if (number <= INT_MIN) - { - object->valueint = INT_MIN; - } - else - { - object->valueint = cJSON_Number; - } - - return object->valuedouble = number; -} - -typedef struct -{ - unsigned char *buffer; - size_t length; - size_t offset; - cjbool noalloc; -} printbuffer; - -/* realloc printbuffer if necessary to have at least "needed" bytes more */ -static unsigned char* ensure(printbuffer * const p, size_t needed, const internal_hooks * const hooks) -{ - unsigned char *newbuffer = NULL; - size_t newsize = 0; - - if ((p == NULL) || (p->buffer == NULL)) - { - return NULL; - } - - if (needed > INT_MAX) - { - /* sizes bigger than INT_MAX are currently not supported */ - return NULL; - } - - needed += p->offset; - if (needed <= p->length) - { - return p->buffer + p->offset; - } - - if (p->noalloc) { - return NULL; - } - - /* calculate new buffer size */ - newsize = needed * 2; - if (newsize > INT_MAX) - { - /* overflow of int, use INT_MAX if possible */ - if (needed <= INT_MAX) - { - newsize = INT_MAX; - } - else - { - return NULL; - } - } - - if (hooks->reallocate != NULL) - { - /* reallocate with realloc if available */ - newbuffer = (unsigned char*)hooks->reallocate(p->buffer, newsize); - } - else - { - /* otherwise reallocate manually */ - newbuffer = (unsigned char*)hooks->allocate(newsize); - if (!newbuffer) - { - hooks->deallocate(p->buffer); - p->length = 0; - p->buffer = NULL; - - return NULL; - } - if (newbuffer) - { - memcpy(newbuffer, p->buffer, p->offset + 1); - } - hooks->deallocate(p->buffer); - } - p->length = newsize; - p->buffer = newbuffer; - - return newbuffer + p->offset; -} - -/* calculate the new length of the string in a printbuffer and update the offset */ -static void update_offset(printbuffer * const buffer) -{ - const unsigned char *buffer_pointer = NULL; - if ((buffer == NULL) || (buffer->buffer == NULL)) - { - return; - } - buffer_pointer = buffer->buffer + buffer->offset; - - buffer->offset += strlen((const char*)buffer_pointer); -} - -/* Render the number nicely from the given item into a string. */ -static unsigned char *print_number(const cJSON * const item, printbuffer * const output_buffer, const internal_hooks * const hooks) -{ - unsigned char *output_pointer = NULL; - double d = item->valuedouble; - - if (output_buffer == NULL) - { - return NULL; - } - - /* value is an int */ - if ((fabs(((double)item->valueint) - d) <= DBL_EPSILON) && (d <= INT_MAX) && (d >= INT_MIN)) - { - /* 2^64+1 can be represented in 21 chars. */ - output_pointer = ensure(output_buffer, 21, hooks); - if (output_pointer != NULL) - { - sprintf((char*)output_pointer, "%d", item->valueint); - } - } - /* value is a floating point number */ - else - { - /* This is a nice tradeoff. */ - output_pointer = ensure(output_buffer, 64, hooks); - if (output_pointer != NULL) - { - /* This checks for NaN and Infinity */ - if ((d * 0) != 0) - { - sprintf((char*)output_pointer, "null"); - } - else if ((fabs(floor(d) - d) <= DBL_EPSILON) && (fabs(d) < 1.0e60)) - { - sprintf((char*)output_pointer, "%.0f", d); - } - else if ((fabs(d) < 1.0e-6) || (fabs(d) > 1.0e9)) - { - sprintf((char*)output_pointer, "%e", d); - } - else - { - sprintf((char*)output_pointer, "%f", d); - } - } - } - - return output_pointer; -} - -/* parse 4 digit hexadecimal number */ -static unsigned parse_hex4(const unsigned char * const input) -{ - unsigned int h = 0; - size_t i = 0; - - for (i = 0; i < 4; i++) - { - /* parse digit */ - if ((input[i] >= '0') && (input[i] <= '9')) - { - h += (unsigned int) input[i] - '0'; - } - else if ((input[i] >= 'A') && (input[i] <= 'F')) - { - h += (unsigned int) 10 + input[i] - 'A'; - } - else if ((input[i] >= 'a') && (input[i] <= 'f')) - { - h += (unsigned int) 10 + input[i] - 'a'; - } - else /* invalid */ - { - return 0; - } - - if (i < 3) - { - /* shift left to make place for the next nibble */ - h = h << 4; - } - } - - return h; -} - -/* converts a UTF-16 literal to UTF-8 - * A literal can be one or two sequences of the form \uXXXX */ -static unsigned char utf16_literal_to_utf8(const unsigned char * const input_pointer, const unsigned char * const input_end, unsigned char **output_pointer, const unsigned char **error_pointer) -{ - /* first bytes of UTF8 encoding for a given length in bytes */ - static const unsigned char firstByteMark[5] = - { - 0x00, /* should never happen */ - 0x00, /* 0xxxxxxx */ - 0xC0, /* 110xxxxx */ - 0xE0, /* 1110xxxx */ - 0xF0 /* 11110xxx */ - }; - - long unsigned int codepoint = 0; - unsigned int first_code = 0; - const unsigned char *first_sequence = input_pointer; - unsigned char utf8_length = 0; - unsigned char sequence_length = 0; - - if ((input_end - first_sequence) < 6) - { - /* input ends unexpectedly */ - *error_pointer = first_sequence; - goto fail; - } - - /* get the first utf16 sequence */ - first_code = parse_hex4(first_sequence + 2); - - /* check that the code is valid */ - if (((first_code >= 0xDC00) && (first_code <= 0xDFFF)) || (first_code == 0)) - { - *error_pointer = first_sequence; - goto fail; - } - - /* UTF16 surrogate pair */ - if ((first_code >= 0xD800) && (first_code <= 0xDBFF)) - { - const unsigned char *second_sequence = first_sequence + 6; - unsigned int second_code = 0; - sequence_length = 12; /* \uXXXX\uXXXX */ - - if ((input_end - second_sequence) < 6) - { - /* input ends unexpectedly */ - *error_pointer = first_sequence; - goto fail; - } - - if ((second_sequence[0] != '\\') || (second_sequence[1] != 'u')) - { - /* missing second half of the surrogate pair */ - *error_pointer = first_sequence; - goto fail; - } - - /* get the second utf16 sequence */ - second_code = parse_hex4(second_sequence + 2); - /* check that the code is valid */ - if ((second_code < 0xDC00) || (second_code > 0xDFFF)) - { - /* invalid second half of the surrogate pair */ - *error_pointer = first_sequence; - goto fail; - } - - - /* calculate the unicode codepoint from the surrogate pair */ - codepoint = 0x10000 + (((first_code & 0x3FF) << 10) | (second_code & 0x3FF)); - } - else - { - sequence_length = 6; /* \uXXXX */ - codepoint = first_code; - } - - /* encode as UTF-8 - * takes at maximum 4 bytes to encode: - * 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx */ - if (codepoint < 0x80) - { - /* normal ascii, encoding 0xxxxxxx */ - utf8_length = 1; - } - else if (codepoint < 0x800) - { - /* two bytes, encoding 110xxxxx 10xxxxxx */ - utf8_length = 2; - } - else if (codepoint < 0x10000) - { - /* three bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx */ - utf8_length = 3; - } - else if (codepoint <= 0x10FFFF) - { - /* four bytes, encoding 1110xxxx 10xxxxxx 10xxxxxx 10xxxxxx */ - utf8_length = 4; - } - else - { - /* invalid unicode codepoint */ - *error_pointer = first_sequence; - goto fail; - } - - /* encode as utf8 */ - switch (utf8_length) - { - case 4: - /* 10xxxxxx */ - (*output_pointer)[3] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - case 3: - /* 10xxxxxx */ - (*output_pointer)[2] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - case 2: - (*output_pointer)[1] = (unsigned char)((codepoint | 0x80) & 0xBF); - codepoint >>= 6; - case 1: - /* depending on the length in bytes this determines the - encoding of the first UTF8 byte */ - (*output_pointer)[0] = (unsigned char)((codepoint | firstByteMark[utf8_length]) & 0xFF); - break; - default: - *error_pointer = first_sequence; - goto fail; - } - *output_pointer += utf8_length; - - return sequence_length; - -fail: - return 0; -} - -/* Parse the input text into an unescaped cinput, and populate item. */ -static const unsigned char *parse_string(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) -{ - const unsigned char *input_pointer = input + 1; - const unsigned char *input_end = input + 1; - unsigned char *output_pointer = NULL; - unsigned char *output = NULL; - - /* not a string */ - if (*input != '\"') - { - *error_pointer = input; - goto fail; - } - - { - /* calculate approximate size of the output (overestimate) */ - size_t allocation_length = 0; - size_t skipped_bytes = 0; - while ((*input_end != '\"') && (*input_end != '\0')) - { - /* is escape sequence */ - if (input_end[0] == '\\') - { - if (input_end[1] == '\0') - { - /* prevent buffer overflow when last input character is a backslash */ - goto fail; - } - skipped_bytes++; - input_end++; - } - input_end++; - } - if (*input_end == '\0') - { - goto fail; /* string ended unexpectedly */ - } - - /* This is at most how much we need for the output */ - allocation_length = (size_t) (input_end - input) - skipped_bytes; - output = (unsigned char*)hooks->allocate(allocation_length + sizeof('\0')); - if (output == NULL) - { - goto fail; /* allocation failure */ - } - } - - output_pointer = output; - /* loop through the string literal */ - while (input_pointer < input_end) - { - if (*input_pointer != '\\') - { - *output_pointer++ = *input_pointer++; - } - /* escape sequence */ - else - { - unsigned char sequence_length = 2; - switch (input_pointer[1]) - { - case 'b': - *output_pointer++ = '\b'; - break; - case 'f': - *output_pointer++ = '\f'; - break; - case 'n': - *output_pointer++ = '\n'; - break; - case 'r': - *output_pointer++ = '\r'; - break; - case 't': - *output_pointer++ = '\t'; - break; - case '\"': - case '\\': - case '/': - *output_pointer++ = input_pointer[1]; - break; - - /* UTF-16 literal */ - case 'u': - sequence_length = utf16_literal_to_utf8(input_pointer, input_end, &output_pointer, error_pointer); - if (sequence_length == 0) - { - /* failed to convert UTF16-literal to UTF-8 */ - goto fail; - } - break; - - default: - *error_pointer = input_pointer; - goto fail; - } - input_pointer += sequence_length; - } - } - - /* zero terminate the output */ - *output_pointer = '\0'; - - item->type = cJSON_String; - item->valuestring = (char*)output; - - return input_end + 1; - -fail: - if (output != NULL) - { - hooks->deallocate(output); - } - - return NULL; -} - -/* Render the cstring provided to an escaped version that can be printed. */ -static unsigned char *print_string_ptr(const unsigned char * const input, printbuffer * const output_buffer, const internal_hooks * const hooks) -{ - const unsigned char *input_pointer = NULL; - unsigned char *output = NULL; - unsigned char *output_pointer = NULL; - size_t output_length = 0; - /* numbers of additional characters needed for escaping */ - size_t escape_characters = 0; - - if (output_buffer == NULL) - { - return NULL; - } - - /* empty string */ - if (input == NULL) - { - output = ensure(output_buffer, sizeof("\"\""), hooks); - if (output == NULL) - { - return NULL; - } - strcpy((char*)output, "\"\""); - - return output; - } - - /* set "flag" to 1 if something needs to be escaped */ - for (input_pointer = input; *input_pointer; input_pointer++) - { - if (strchr("\"\\\b\f\n\r\t", *input_pointer)) - { - /* one character escape sequence */ - escape_characters++; - } - else if (*input_pointer < 32) - { - /* UTF-16 escape sequence uXXXX */ - escape_characters += 5; - } - } - output_length = (size_t)(input_pointer - input) + escape_characters; - - output = ensure(output_buffer, output_length + sizeof("\"\""), hooks); - if (output == NULL) - { - return NULL; - } - - /* no characters have to be escaped */ - if (escape_characters == 0) - { - output[0] = '\"'; - memcpy(output + 1, input, output_length); - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return output; - } - - output[0] = '\"'; - output_pointer = output + 1; - /* copy the string */ - for (input_pointer = input; *input_pointer != '\0'; input_pointer++, output_pointer++) - { - if ((*input_pointer > 31) && (*input_pointer != '\"') && (*input_pointer != '\\')) - { - /* normal character, copy */ - *output_pointer = *input_pointer; - } - else - { - /* character needs to be escaped */ - *output_pointer++ = '\\'; - switch (*input_pointer) - { - case '\\': - *output_pointer = '\\'; - break; - case '\"': - *output_pointer = '\"'; - break; - case '\b': - *output_pointer = 'b'; - break; - case '\f': - *output_pointer = 'f'; - break; - case '\n': - *output_pointer = 'n'; - break; - case '\r': - *output_pointer = 'r'; - break; - case '\t': - *output_pointer = 't'; - break; - default: - /* escape and print as unicode codepoint */ - sprintf((char*)output_pointer, "u%04x", *input_pointer); - output_pointer += 4; - break; - } - } - } - output[output_length + 1] = '\"'; - output[output_length + 2] = '\0'; - - return output; -} - -/* Invoke print_string_ptr (which is useful) on an item. */ -static unsigned char *print_string(const cJSON * const item, printbuffer * const p, const internal_hooks * const hooks) -{ - return print_string_ptr((unsigned char*)item->valuestring, p, hooks); -} - -/* Predeclare these prototypes. */ -static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); -static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); -static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const ep, const internal_hooks * const hooks); -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks); - -/* Utility to jump whitespace and cr/lf */ -static const unsigned char *skip_whitespace(const unsigned char *in) -{ - while (in && *in && (*in <= 32)) - { - in++; - } - - return in; -} - -/* Parse an object - create a new root, and populate. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cjbool require_null_terminated) -{ - const unsigned char *end = NULL; - /* use global error pointer if no specific one was given */ - const unsigned char **ep = return_parse_end ? (const unsigned char**)return_parse_end : &global_ep; - cJSON *c = cJSON_New_Item(&global_hooks); - *ep = NULL; - if (!c) /* memory fail */ - { - return NULL; - } - - end = parse_value(c, skip_whitespace((const unsigned char*)value), ep, &global_hooks); - if (!end) - { - /* parse failure. ep is set. */ - cJSON_Delete(c); - return NULL; - } - - /* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */ - if (require_null_terminated) - { - end = skip_whitespace(end); - if (*end) - { - cJSON_Delete(c); - *ep = end; - return NULL; - } - } - if (return_parse_end) - { - *return_parse_end = (const char*)end; - } - - return c; -} - -/* Default options for cJSON_Parse */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value) -{ - return cJSON_ParseWithOpts(value, 0, 0); -} - -#ifndef min -#define min(a, b) ((a < b) ? a : b) -#endif - -static unsigned char *print(const cJSON * const item, cjbool format, const internal_hooks * const hooks) -{ - printbuffer buffer[1]; - unsigned char *printed = NULL; - - memset(buffer, 0, sizeof(buffer)); - - /* create buffer */ - buffer->buffer = (unsigned char*) hooks->allocate(256); - if (buffer->buffer == NULL) - { - goto fail; - } - - /* print the value */ - if (print_value(item, 0, format, buffer, hooks) == NULL) - { - goto fail; - } - update_offset(buffer); - - /* copy the buffer over to a new one */ - printed = (unsigned char*) hooks->allocate(buffer->offset + 1); - if (printed == NULL) - { - goto fail; - } - strncpy((char*)printed, (char*)buffer->buffer, min(buffer->length, buffer->offset + 1)); - printed[buffer->offset] = '\0'; /* just to be sure */ - - /* free the buffer */ - hooks->deallocate(buffer->buffer); - - return printed; - -fail: - if (buffer->buffer != NULL) - { - hooks->deallocate(buffer->buffer); - } - - if (printed != NULL) - { - hooks->deallocate(printed); - } - - return NULL; -} - -/* Render a cJSON item/entity/structure to text. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item) -{ - return (char*)print(item, true, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item) -{ - return (char*)print(item, false, &global_hooks); -} - -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, cjbool fmt) -{ - printbuffer p; - - if (prebuffer < 0) - { - return NULL; - } - - p.buffer = (unsigned char*)global_hooks.allocate((size_t)prebuffer); - if (!p.buffer) - { - return NULL; - } - - p.length = (size_t)prebuffer; - p.offset = 0; - p.noalloc = false; - - return (char*)print_value(item, 0, fmt, &p, &global_hooks); -} - -CJSON_PUBLIC(int) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const cjbool fmt) -{ - printbuffer p; - - if (len < 0) - { - return false; - } - - p.buffer = (unsigned char*)buf; - p.length = (size_t)len; - p.offset = 0; - p.noalloc = true; - return print_value(item, 0, fmt, &p, &global_hooks) != NULL; -} - -/* Parser core - when encountering text, process appropriately. */ -static const unsigned char *parse_value(cJSON * const item, const unsigned char * const input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) -{ - if (input == NULL) - { - return NULL; /* no input */ - } - - /* parse the different types of values */ - /* null */ - if (!strncmp((const char*)input, "null", 4)) - { - item->type = cJSON_NULL; - return input + 4; - } - /* false */ - if (!strncmp((const char*)input, "false", 5)) - { - item->type = cJSON_False; - return input + 5; - } - /* true */ - if (!strncmp((const char*)input, "true", 4)) - { - item->type = cJSON_True; - item->valueint = 1; - return input + 4; - } - /* string */ - if (*input == '\"') - { - return parse_string(item, input, error_pointer, hooks); - } - /* number */ - if ((*input == '-') || ((*input >= '0') && (*input <= '9'))) - { - return parse_number(item, input); - } - /* array */ - if (*input == '[') - { - return parse_array(item, input, error_pointer, hooks); - } - /* object */ - if (*input == '{') - { - return parse_object(item, input, error_pointer, hooks); - } - - /* failure. */ - *error_pointer = input; - return NULL; -} - -/* Render a value to text. */ -static unsigned char *print_value(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) -{ - unsigned char *output = NULL; - - if ((item == NULL) || (output_buffer == NULL)) - { - return NULL; - } - - switch ((item->type) & 0xFF) - { - case cJSON_NULL: - output = ensure(output_buffer, 5, hooks); - if (output != NULL) - { - strcpy((char*)output, "null"); - } - break; - case cJSON_False: - output = ensure(output_buffer, 6, hooks); - if (output != NULL) - { - strcpy((char*)output, "false"); - } - break; - case cJSON_True: - output = ensure(output_buffer, 5, hooks); - if (output != NULL) - { - strcpy((char*)output, "true"); - } - break; - case cJSON_Number: - output = print_number(item, output_buffer, hooks); - break; - case cJSON_Raw: - { - size_t raw_length = 0; - if (item->valuestring == NULL) - { - if (!output_buffer->noalloc) - { - hooks->deallocate(output_buffer->buffer); - } - output = NULL; - break; - } - - raw_length = strlen(item->valuestring) + sizeof('\0'); - output = ensure(output_buffer, raw_length, hooks); - if (output != NULL) - { - memcpy(output, item->valuestring, raw_length); - } - break; - } - case cJSON_String: - output = print_string(item, output_buffer, hooks); - break; - case cJSON_Array: - output = print_array(item, depth, format, output_buffer, hooks); - break; - case cJSON_Object: - output = print_object(item, depth, format, output_buffer, hooks); - break; - default: - output = NULL; - break; - } - - return output; -} - -/* Build an array from input text. */ -static const unsigned char *parse_array(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) -{ - cJSON *head = NULL; /* head of the linked list */ - cJSON *current_item = NULL; - - if (*input != '[') - { - /* not an array */ - *error_pointer = input; - goto fail; - } - - input = skip_whitespace(input + 1); - if (*input == ']') - { - /* empty array */ - goto success; - } - - /* step back to character in front of the first element */ - input--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(hooks); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse next value */ - input = skip_whitespace(input + 1); - input = parse_value(current_item, input, error_pointer, hooks); - input = skip_whitespace(input); - if (input == NULL) - { - goto fail; /* failed to parse value */ - } - } - while (*input == ','); - - if (*input != ']') - { - *error_pointer = input; - goto fail; /* expected end of array */ - } - -success: - item->type = cJSON_Array; - item->child = head; - - return input + 1; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return NULL; -} - -/* Render an array to text */ -static unsigned char *print_array(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) -{ - unsigned char *output = NULL; - unsigned char *output_pointer = NULL; - size_t length = 0; - cJSON *current_element = item->child; - size_t output_offset = 0; - - if (output_buffer == NULL) - { - return NULL; - } - - /* Compose the output array. */ - /* opening square bracket */ - output_offset = output_buffer->offset; - output_pointer = ensure(output_buffer, 1, hooks); - if (output_pointer == NULL) - { - return NULL; - } - - *output_pointer = '['; - output_buffer->offset++; - - while (current_element != NULL) - { - if (print_value(current_element, depth + 1, format, output_buffer, hooks) == NULL) - { - return NULL; - } - update_offset(output_buffer); - if (current_element->next) - { - length = format ? 2 : 1; - output_pointer = ensure(output_buffer, length + 1, hooks); - if (output_pointer == NULL) - { - return NULL; - } - *output_pointer++ = ','; - if(format) - { - *output_pointer++ = ' '; - } - *output_pointer = '\0'; - output_buffer->offset += length; - } - current_element = current_element->next; - } - - output_pointer = ensure(output_buffer, 2, hooks); - if (output_pointer == NULL) - { - return NULL; - } - *output_pointer++ = ']'; - *output_pointer = '\0'; - output = output_buffer->buffer + output_offset; - - return output; -} - -/* Build an object from the text. */ -static const unsigned char *parse_object(cJSON * const item, const unsigned char *input, const unsigned char ** const error_pointer, const internal_hooks * const hooks) -{ - cJSON *head = NULL; /* linked list head */ - cJSON *current_item = NULL; - - if (*input != '{') - { - *error_pointer = input; - goto fail; /* not an object */ - } - - input = skip_whitespace(input + 1); - if (*input == '}') - { - goto success; /* empty object */ - } - - /* step back to character in front of the first element */ - input--; - /* loop through the comma separated array elements */ - do - { - /* allocate next item */ - cJSON *new_item = cJSON_New_Item(hooks); - if (new_item == NULL) - { - goto fail; /* allocation failure */ - } - - /* attach next item to list */ - if (head == NULL) - { - /* start the linked list */ - current_item = head = new_item; - } - else - { - /* add to the end and advance */ - current_item->next = new_item; - new_item->prev = current_item; - current_item = new_item; - } - - /* parse the name of the child */ - input = skip_whitespace(input + 1); - input = parse_string(current_item, input, error_pointer, hooks); - input = skip_whitespace(input); - if (input == NULL) - { - goto fail; /* faile to parse name */ - } - - /* swap valuestring and string, because we parsed the name */ - current_item->string = current_item->valuestring; - current_item->valuestring = NULL; - - if (*input != ':') - { - *error_pointer = input; - goto fail; /* invalid object */ - } - - /* parse the value */ - input = skip_whitespace(input + 1); - input = parse_value(current_item, input, error_pointer, hooks); - input = skip_whitespace(input); - if (input == NULL) - { - goto fail; /* failed to parse value */ - } - } - while (*input == ','); - - if (*input != '}') - { - *error_pointer = input; - goto fail; /* expected end of object */ - } - -success: - item->type = cJSON_Object; - item->child = head; - - return input + 1; - -fail: - if (head != NULL) - { - cJSON_Delete(head); - } - - return NULL; -} - -/* Render an object to text. */ -static unsigned char *print_object(const cJSON * const item, const size_t depth, const cjbool format, printbuffer * const output_buffer, const internal_hooks * const hooks) -{ - unsigned char *output = NULL; - unsigned char *output_pointer = NULL; - size_t length = 0; - size_t output_offset = 0; - cJSON *current_item = item->child; - - if (output_buffer == NULL) - { - return NULL; - } - - /* Compose the output: */ - output_offset = output_buffer->offset; - length = format ? 2 : 1; /* fmt: {\n */ - output_pointer = ensure(output_buffer, length + 1, hooks); - if (output_pointer == NULL) - { - return NULL; - } - - *output_pointer++ = '{'; - if (format) - { - *output_pointer++ = '\n'; - } - output_buffer->offset += length; - - while (current_item) - { - if (format) - { - size_t i; - output_pointer = ensure(output_buffer, depth + 1, hooks); - if (output_pointer == NULL) - { - return NULL; - } - for (i = 0; i < depth + 1; i++) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += depth + 1; - } - - /* print key */ - if (print_string_ptr((unsigned char*)current_item->string, output_buffer, hooks) == NULL) - { - return NULL; - } - update_offset(output_buffer); - - length = format ? 2 : 1; - output_pointer = ensure(output_buffer, length, hooks); - if (output_pointer == NULL) - { - return NULL; - } - *output_pointer++ = ':'; - if (format) - { - *output_pointer++ = '\t'; - } - output_buffer->offset += length; - - /* print value */ - if (!print_value(current_item, depth + 1, format, output_buffer, hooks)) - { - return NULL; - } - update_offset(output_buffer); - - /* print comma if not last */ - length = (size_t) (format ? 1 : 0) + (current_item->next ? 1 : 0); - output_pointer = ensure(output_buffer, length + 1, hooks); - if (output_pointer == NULL) - { - return NULL; - } - if (current_item->next) - { - *output_pointer++ = ','; - } - - if (format) - { - *output_pointer++ = '\n'; - } - *output_pointer = '\0'; - output_buffer->offset += length; - - current_item = current_item->next; - } - - output_pointer = ensure(output_buffer, format ? (depth + 2) : 2, hooks); - if (output_pointer == NULL) - { - return NULL; - } - if (format) - { - size_t i; - for (i = 0; i < (depth); i++) - { - *output_pointer++ = '\t'; - } - } - *output_pointer++ = '}'; - *output_pointer = '\0'; - output = (output_buffer->buffer) + output_offset; - - return output; -} - -/* Get Array size/item / object item. */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array) -{ - cJSON *c = array->child; - size_t i = 0; - while(c) - { - i++; - c = c->next; - } - - /* FIXME: Can overflow here. Cannot be fixed without breaking the API */ - - return (int)i; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item) -{ - cJSON *c = array ? array->child : NULL; - while (c && item > 0) - { - item--; - c = c->next; - } - - return c; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string) -{ - cJSON *c = object ? object->child : NULL; - while (c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string)) - { - c = c->next; - } - return c; -} - -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string) -{ - cJSON *current_element = NULL; - - if ((object == NULL) || (string == NULL)) - { - return NULL; - } - - current_element = object->child; - while ((current_element != NULL) && (strcmp(string, current_element->string) != 0)) - { - current_element = current_element->next; - } - - return current_element; -} - -CJSON_PUBLIC(cjbool) cJSON_HasObjectItem(const cJSON *object, const char *string) -{ - return cJSON_GetObjectItem(object, string) ? 1 : 0; -} - -/* Utility for array list handling. */ -static void suffix_object(cJSON *prev, cJSON *item) -{ - prev->next = item; - item->prev = prev; -} - -/* Utility for handling references. */ -static cJSON *create_reference(const cJSON *item, const internal_hooks * const hooks) -{ - cJSON *ref = cJSON_New_Item(hooks); - if (!ref) - { - return NULL; - } - memcpy(ref, item, sizeof(cJSON)); - ref->string = NULL; - ref->type |= cJSON_IsReference; - ref->next = ref->prev = NULL; - return ref; -} - -/* Add item to array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item) -{ - cJSON *child = NULL; - - if ((item == NULL) || (array == NULL)) - { - return; - } - - child = array->child; - - if (child == NULL) - { - /* list is empty, start new one */ - array->child = item; - } - else - { - /* append to the end */ - while (child->next) - { - child = child->next; - } - suffix_object(child, item); - } -} - -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) -{ - /* call cJSON_AddItemToObjectCS for code reuse */ - cJSON_AddItemToObjectCS(object, (char*)cJSON_strdup((const unsigned char*)string, &global_hooks), item); - /* remove cJSON_StringIsConst flag */ - item->type &= ~cJSON_StringIsConst; -} - -/* Add an item to an object with constant string as key */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item) -{ - if (!item) - { - return; - } - if (!(item->type & cJSON_StringIsConst) && item->string) - { - global_hooks.deallocate(item->string); - } -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wcast-qual" -#endif - item->string = (char*)string; -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - item->type |= cJSON_StringIsConst; - cJSON_AddItemToArray(object, item); -} - -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item) -{ - cJSON_AddItemToArray(array, create_reference(item, &global_hooks)); -} - -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item) -{ - cJSON_AddItemToObject(object, string, create_reference(item, &global_hooks)); -} - -static cJSON *DetachItemFromArray(cJSON *array, size_t which) -{ - cJSON *c = array->child; - while (c && (which > 0)) - { - c = c->next; - which--; - } - if (!c) - { - /* item doesn't exist */ - return NULL; - } - if (c->prev) - { - /* not the first element */ - c->prev->next = c->next; - } - if (c->next) - { - c->next->prev = c->prev; - } - if (c==array->child) - { - array->child = c->next; - } - /* make sure the detached item doesn't point anywhere anymore */ - c->prev = c->next = NULL; - - return c; -} -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which) -{ - if (which < 0) - { - return NULL; - } - - return DetachItemFromArray(array, (size_t)which); -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which) -{ - cJSON_Delete(cJSON_DetachItemFromArray(array, which)); -} - -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string) -{ - size_t i = 0; - cJSON *c = object->child; - while (c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string)) - { - i++; - c = c->next; - } - if (c) - { - return DetachItemFromArray(object, i); - } - - return NULL; -} - -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string) -{ - cJSON_Delete(cJSON_DetachItemFromObject(object, string)); -} - -/* Replace array/object items with new ones. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem) -{ - cJSON *c = array->child; - while (c && (which > 0)) - { - c = c->next; - which--; - } - if (!c) - { - cJSON_AddItemToArray(array, newitem); - return; - } - newitem->next = c; - newitem->prev = c->prev; - c->prev = newitem; - if (c == array->child) - { - array->child = newitem; - } - else - { - newitem->prev->next = newitem; - } -} - -static void ReplaceItemInArray(cJSON *array, size_t which, cJSON *newitem) -{ - cJSON *c = array->child; - while (c && (which > 0)) - { - c = c->next; - which--; - } - if (!c) - { - return; - } - newitem->next = c->next; - newitem->prev = c->prev; - if (newitem->next) - { - newitem->next->prev = newitem; - } - if (c == array->child) - { - array->child = newitem; - } - else - { - newitem->prev->next = newitem; - } - c->next = c->prev = NULL; - cJSON_Delete(c); -} -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem) -{ - if (which < 0) - { - return; - } - - ReplaceItemInArray(array, (size_t)which, newitem); -} - -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object, const char *string, cJSON *newitem) -{ - size_t i = 0; - cJSON *c = object->child; - while(c && cJSON_strcasecmp((unsigned char*)c->string, (const unsigned char*)string)) - { - i++; - c = c->next; - } - if(c) - { - /* free the old string if not const */ - if (!(newitem->type & cJSON_StringIsConst) && newitem->string) - { - global_hooks.deallocate(newitem->string); - } - - newitem->string = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - ReplaceItemInArray(object, i, newitem); - } -} - -/* Create basic types: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_NULL; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_True; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cjbool b) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = b ? cJSON_True : cJSON_False; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Number; - item->valuedouble = num; - - /* use saturation in case of overflow */ - if (num >= INT_MAX) - { - item->valueint = INT_MAX; - } - else if (num <= INT_MIN) - { - item->valueint = INT_MIN; - } - else - { - item->valueint = (int)num; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_String; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)string, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type = cJSON_Raw; - item->valuestring = (char*)cJSON_strdup((const unsigned char*)raw, &global_hooks); - if(!item->valuestring) - { - cJSON_Delete(item); - return NULL; - } - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if(item) - { - item->type=cJSON_Array; - } - - return item; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void) -{ - cJSON *item = cJSON_New_Item(&global_hooks); - if (item) - { - item->type = cJSON_Object; - } - - return item; -} - -/* Create Arrays: */ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if (count < 0) - { - return NULL; - } - - a = cJSON_CreateArray(); - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if (!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if (count < 0) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if (count < 0) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for(i = 0;a && (i < (size_t)count); i++) - { - n = cJSON_CreateNumber(numbers[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p, n); - } - p = n; - } - - return a; -} - -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count) -{ - size_t i = 0; - cJSON *n = NULL; - cJSON *p = NULL; - cJSON *a = NULL; - - if (count < 0) - { - return NULL; - } - - a = cJSON_CreateArray(); - - for (i = 0; a && (i < (size_t)count); i++) - { - n = cJSON_CreateString(strings[i]); - if(!n) - { - cJSON_Delete(a); - return NULL; - } - if(!i) - { - a->child = n; - } - else - { - suffix_object(p,n); - } - p = n; - } - - return a; -} - -/* Duplication */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, cjbool recurse) -{ - cJSON *newitem = NULL; - cJSON *child = NULL; - cJSON *next = NULL; - cJSON *newchild = NULL; - - /* Bail on bad ptr */ - if (!item) - { - goto fail; - } - /* Create new item */ - newitem = cJSON_New_Item(&global_hooks); - if (!newitem) - { - goto fail; - } - /* Copy over all vars */ - newitem->type = item->type & (~cJSON_IsReference); - newitem->valueint = item->valueint; - newitem->valuedouble = item->valuedouble; - if (item->valuestring) - { - newitem->valuestring = (char*)cJSON_strdup((unsigned char*)item->valuestring, &global_hooks); - if (!newitem->valuestring) - { - goto fail; - } - } - if (item->string) - { - newitem->string = (item->type&cJSON_StringIsConst) ? item->string : (char*)cJSON_strdup((unsigned char*)item->string, &global_hooks); - if (!newitem->string) - { - goto fail; - } - } - /* If non-recursive, then we're done! */ - if (!recurse) - { - return newitem; - } - /* Walk the ->next chain for the child. */ - child = item->child; - while (child != NULL) - { - newchild = cJSON_Duplicate(child, true); /* Duplicate (with recurse) each item in the ->next chain */ - if (!newchild) - { - goto fail; - } - if (next != NULL) - { - /* If newitem->child already set, then crosswire ->prev and ->next and move on */ - next->next = newchild; - newchild->prev = next; - next = newchild; - } - else - { - /* Set newitem->child and move to it */ - newitem->child = newchild; - next = newchild; - } - child = child->next; - } - - return newitem; - -fail: - if (newitem != NULL) - { - cJSON_Delete(newitem); - } - - return NULL; -} - -CJSON_PUBLIC(void) cJSON_Minify(char *json) -{ - unsigned char *into = (unsigned char*)json; - while (*json) - { - if (*json == ' ') - { - json++; - } - else if (*json == '\t') - { - /* Whitespace characters. */ - json++; - } - else if (*json == '\r') - { - json++; - } - else if (*json=='\n') - { - json++; - } - else if ((*json == '/') && (json[1] == '/')) - { - /* double-slash comments, to end of line. */ - while (*json && (*json != '\n')) - { - json++; - } - } - else if ((*json == '/') && (json[1] == '*')) - { - /* multiline comments. */ - while (*json && !((*json == '*') && (json[1] == '/'))) - { - json++; - } - json += 2; - } - else if (*json == '\"') - { - /* string literals, which are \" sensitive. */ - *into++ = (unsigned char)*json++; - while (*json && (*json != '\"')) - { - if (*json == '\\') - { - *into++ = (unsigned char)*json++; - } - *into++ = (unsigned char)*json++; - } - *into++ = (unsigned char)*json++; - } - else - { - /* All other characters. */ - *into++ = (unsigned char)*json++; - } - } - - /* and null-terminate. */ - *into = '\0'; -} diff --git a/libs/libks/src/cJSON_Utils.c b/libs/libks/src/cJSON_Utils.c deleted file mode 100644 index 24454b5d45..0000000000 --- a/libs/libks/src/cJSON_Utils.c +++ /dev/null @@ -1,881 +0,0 @@ -#include -#include -#include -#include -#include - -#include "ks_cJSON_Utils.h" - -static unsigned char* cJSONUtils_strdup(const unsigned char* str) -{ - size_t len = 0; - unsigned char *copy = NULL; - - len = strlen((const char*)str) + 1; - if (!(copy = (unsigned char*)malloc(len))) - { - return NULL; - } - memcpy(copy, str, len); - - return copy; -} - -static int cJSONUtils_strcasecmp(const unsigned char *s1, const unsigned char *s2) -{ - if (!s1) - { - return (s1 == s2) ? 0 : 1; /* both NULL? */ - } - if (!s2) - { - return 1; - } - for(; tolower(*s1) == tolower(*s2); ++s1, ++s2) - { - if(*s1 == 0) - { - return 0; - } - } - - return tolower(*s1) - tolower(*s2); -} - -/* JSON Pointer implementation: */ -static int cJSONUtils_Pstrcasecmp(const unsigned char *a, const unsigned char *e) -{ - if (!a || !e) - { - return (a == e) ? 0 : 1; /* both NULL? */ - } - for (; *a && *e && (*e != '/'); a++, e++) /* compare until next '/' */ - { - if (*e == '~') - { - /* check for escaped '~' (~0) and '/' (~1) */ - if (!((e[1] == '0') && (*a == '~')) && !((e[1] == '1') && (*a == '/'))) - { - /* invalid escape sequence or wrong character in *a */ - return 1; - } - else - { - e++; - } - } - else if (tolower(*a) != tolower(*e)) - { - return 1; - } - } - if (((*e != 0) && (*e != '/')) != (*a != 0)) - { - /* one string has ended, the other not */ - return 1; - } - - return 0; -} - -static size_t cJSONUtils_PointerEncodedstrlen(const unsigned char *s) -{ - size_t l = 0; - for (; *s; s++, l++) - { - if ((*s == '~') || (*s == '/')) - { - l++; - } - } - - return l; -} - -static void cJSONUtils_PointerEncodedstrcpy(unsigned char *d, const unsigned char *s) -{ - for (; *s; s++) - { - if (*s == '/') - { - *d++ = '~'; - *d++ = '1'; - } - else if (*s == '~') - { - *d++ = '~'; - *d++ = '0'; - } - else - { - *d++ = *s; - } - } - - *d = '\0'; -} - -CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target) -{ - int type = object->type; - size_t c = 0; - cJSON *obj = 0; - - if (object == target) - { - /* found */ - return (char*)cJSONUtils_strdup((const unsigned char*)""); - } - - /* recursively search all children of the object */ - for (obj = object->child; obj; obj = obj->next, c++) - { - unsigned char *found = (unsigned char*)cJSONUtils_FindPointerFromObjectTo(obj, target); - if (found) - { - if ((type & 0xFF) == cJSON_Array) - { - /* reserve enough memory for a 64 bit integer + '/' and '\0' */ - unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + 23); - /* check if conversion to unsigned long is valid - * This should be eliminated at compile time by dead code elimination - * if size_t is an alias of unsigned long, or if it is bigger */ - if (c > ULONG_MAX) - { - free(found); - return NULL; - } - sprintf((char*)ret, "/%lu%s", (unsigned long)c, found); /* / */ - free(found); - - return (char*)ret; - } - else if ((type & 0xFF) == cJSON_Object) - { - unsigned char *ret = (unsigned char*)malloc(strlen((char*)found) + cJSONUtils_PointerEncodedstrlen((unsigned char*)obj->string) + 2); - *ret = '/'; - cJSONUtils_PointerEncodedstrcpy(ret + 1, (unsigned char*)obj->string); - strcat((char*)ret, (char*)found); - free(found); - - return (char*)ret; - } - - /* reached leaf of the tree, found nothing */ - free(found); - return NULL; - } - } - - /* not found */ - return NULL; -} - -CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer) -{ - /* follow path of the pointer */ - while ((*pointer++ == '/') && object) - { - if ((object->type & 0xFF) == cJSON_Array) - { - size_t which = 0; - /* parse array index */ - while ((*pointer >= '0') && (*pointer <= '9')) - { - which = (10 * which) + (size_t)(*pointer++ - '0'); - } - if (*pointer && (*pointer != '/')) - { - /* not end of string or new path token */ - return NULL; - } - if (which > INT_MAX) - { - return NULL; - } - object = cJSON_GetArrayItem(object, (int)which); - } - else if ((object->type & 0xFF) == cJSON_Object) - { - object = object->child; - /* GetObjectItem. */ - while (object && cJSONUtils_Pstrcasecmp((unsigned char*)object->string, (const unsigned char*)pointer)) - { - object = object->next; - } - /* skip to the next path token or end of string */ - while (*pointer && (*pointer != '/')) - { - pointer++; - } - } - else - { - return NULL; - } - } - - return object; -} - -/* JSON Patch implementation. */ -static void cJSONUtils_InplaceDecodePointerString(unsigned char *string) -{ - unsigned char *s2 = string; - - if (string == NULL) { - return; - } - - for (; *string; s2++, string++) - { - *s2 = (*string != '~') - ? (*string) - : ((*(++string) == '0') - ? '~' - : '/'); - } - - *s2 = '\0'; -} - -static cJSON *cJSONUtils_PatchDetach(cJSON *object, const unsigned char *path) -{ - unsigned char *parentptr = NULL; - unsigned char *childptr = NULL; - cJSON *parent = NULL; - cJSON *ret = NULL; - - /* copy path and split it in parent and child */ - parentptr = cJSONUtils_strdup(path); - if (parentptr == NULL) { - return NULL; - } - - childptr = (unsigned char*)strrchr((char*)parentptr, '/'); /* last '/' */ - if (childptr == NULL) - { - free(parentptr); - return NULL; - } - /* split strings */ - *childptr++ = '\0'; - - parent = cJSONUtils_GetPointer(object, (char*)parentptr); - cJSONUtils_InplaceDecodePointerString(childptr); - - if (!parent) - { - /* Couldn't find object to remove child from. */ - ret = NULL; - } - else if ((parent->type & 0xFF) == cJSON_Array) - { - ret = cJSON_DetachItemFromArray(parent, atoi((char*)childptr)); - } - else if ((parent->type & 0xFF) == cJSON_Object) - { - ret = cJSON_DetachItemFromObject(parent, (char*)childptr); - } - free(parentptr); - - /* return the detachted item */ - return ret; -} - -static int cJSONUtils_Compare(cJSON *a, cJSON *b) -{ - if ((a == NULL) || (b == NULL) || ((a->type & 0xFF) != (b->type & 0xFF))) - { - /* mismatched type. */ - return -1; - } - switch (a->type & 0xFF) - { - case cJSON_Number: - /* numeric mismatch. */ - return ((a->valueint != b->valueint) || (a->valuedouble != b->valuedouble)) ? -2 : 0; - case cJSON_String: - /* string mismatch. */ - return (strcmp(a->valuestring, b->valuestring) != 0) ? -3 : 0; - case cJSON_Array: - for (a = a->child, b = b->child; a && b; a = a->next, b = b->next) - { - int err = cJSONUtils_Compare(a, b); - if (err) - { - return err; - } - } - /* array size mismatch? (one of both children is not NULL) */ - return (a || b) ? -4 : 0; - case cJSON_Object: - cJSONUtils_SortObject(a); - cJSONUtils_SortObject(b); - a = a->child; - b = b->child; - while (a && b) - { - int err = 0; - /* compare object keys */ - if (cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string)) - { - /* missing member */ - return -6; - } - err = cJSONUtils_Compare(a, b); - if (err) - { - return err; - } - a = a->next; - b = b->next; - } - /* object length mismatch (one of both children is not null) */ - return (a || b) ? -5 : 0; - - default: - break; - } - /* null, true or false */ - return 0; -} - -static int cJSONUtils_ApplyPatch(cJSON *object, cJSON *patch) -{ - cJSON *op = NULL; - cJSON *path = NULL; - cJSON *value = NULL; - cJSON *parent = NULL; - int opcode = 0; - unsigned char *parentptr = NULL; - unsigned char *childptr = NULL; - - op = cJSON_GetObjectItem(patch, "op"); - path = cJSON_GetObjectItem(patch, "path"); - if (!op || !path) - { - /* malformed patch. */ - return 2; - } - - /* decode operation */ - if (!strcmp(op->valuestring, "add")) - { - opcode = 0; - } - else if (!strcmp(op->valuestring, "remove")) - { - opcode = 1; - } - else if (!strcmp(op->valuestring, "replace")) - { - opcode = 2; - } - else if (!strcmp(op->valuestring, "move")) - { - opcode = 3; - } - else if (!strcmp(op->valuestring, "copy")) - { - opcode = 4; - } - else if (!strcmp(op->valuestring, "test")) - { - /* compare value: {...} with the given path */ - return cJSONUtils_Compare(cJSONUtils_GetPointer(object, path->valuestring), cJSON_GetObjectItem(patch, "value")); - } - else - { - /* unknown opcode. */ - return 3; - } - - /* Remove/Replace */ - if ((opcode == 1) || (opcode == 2)) - { - /* Get rid of old. */ - cJSON_Delete(cJSONUtils_PatchDetach(object, (unsigned char*)path->valuestring)); - if (opcode == 1) - { - /* For Remove, this is job done. */ - return 0; - } - } - - /* Copy/Move uses "from". */ - if ((opcode == 3) || (opcode == 4)) - { - cJSON *from = cJSON_GetObjectItem(patch, "from"); - if (!from) - { - /* missing "from" for copy/move. */ - return 4; - } - - if (opcode == 3) - { - /* move */ - value = cJSONUtils_PatchDetach(object, (unsigned char*)from->valuestring); - } - if (opcode == 4) - { - /* copy */ - value = cJSONUtils_GetPointer(object, from->valuestring); - } - if (!value) - { - /* missing "from" for copy/move. */ - return 5; - } - if (opcode == 4) - { - value = cJSON_Duplicate(value, 1); - } - if (!value) - { - /* out of memory for copy/move. */ - return 6; - } - } - else /* Add/Replace uses "value". */ - { - value = cJSON_GetObjectItem(patch, "value"); - if (!value) - { - /* missing "value" for add/replace. */ - return 7; - } - value = cJSON_Duplicate(value, 1); - if (!value) - { - /* out of memory for add/replace. */ - return 8; - } - } - - /* Now, just add "value" to "path". */ - - /* split pointer in parent and child */ - parentptr = cJSONUtils_strdup((unsigned char*)path->valuestring); - childptr = (unsigned char*)strrchr((char*)parentptr, '/'); - if (childptr) - { - *childptr++ = '\0'; - } - parent = cJSONUtils_GetPointer(object, (char*)parentptr); - cJSONUtils_InplaceDecodePointerString(childptr); - - /* add, remove, replace, move, copy, test. */ - if (!parent) - { - /* Couldn't find object to add to. */ - free(parentptr); - cJSON_Delete(value); - return 9; - } - else if ((parent->type & 0xFF) == cJSON_Array) - { - if (!strcmp((char*)childptr, "-")) - { - cJSON_AddItemToArray(parent, value); - } - else - { - cJSON_InsertItemInArray(parent, atoi((char*)childptr), value); - } - } - else if ((parent->type & 0xFF) == cJSON_Object) - { - cJSON_DeleteItemFromObject(parent, (char*)childptr); - cJSON_AddItemToObject(parent, (char*)childptr, value); - } - else - { - cJSON_Delete(value); - } - free(parentptr); - - return 0; -} - -CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches) -{ - int err = 0; - - if (patches == NULL) - { - return 1; - } - - if ((patches->type & 0xFF) != cJSON_Array) - { - /* malformed patches. */ - return 1; - } - if (patches) - { - patches = patches->child; - } - while (patches) - { - if ((err = cJSONUtils_ApplyPatch(object, patches))) - { - return err; - } - patches = patches->next; - } - - return 0; -} - -static void cJSONUtils_GeneratePatch(cJSON *patches, const unsigned char *op, const unsigned char *path, const unsigned char *suffix, cJSON *val) -{ - cJSON *patch = cJSON_CreateObject(); - cJSON_AddItemToObject(patch, "op", cJSON_CreateString((const char*)op)); - if (suffix) - { - unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen(suffix) + 2); - cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", (const char*)path), suffix); - cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)newpath)); - free(newpath); - } - else - { - cJSON_AddItemToObject(patch, "path", cJSON_CreateString((const char*)path)); - } - if (val) - { - cJSON_AddItemToObject(patch, "value", cJSON_Duplicate(val, 1)); - } - cJSON_AddItemToArray(patches, patch); -} - -CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val) -{ - cJSONUtils_GeneratePatch(array, (const unsigned char*)op, (const unsigned char*)path, 0, val); -} - -static void cJSONUtils_CompareToPatch(cJSON *patches, const unsigned char *path, cJSON *from, cJSON *to) -{ - if ((from == NULL) || (to == NULL)) - { - return; - } - - if ((from->type & 0xFF) != (to->type & 0xFF)) - { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to); - return; - } - - switch ((from->type & 0xFF)) - { - case cJSON_Number: - if ((from->valueint != to->valueint) || (from->valuedouble != to->valuedouble)) - { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to); - } - return; - - case cJSON_String: - if (strcmp(from->valuestring, to->valuestring) != 0) - { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"replace", path, 0, to); - } - return; - - case cJSON_Array: - { - size_t c = 0; - unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + 23); /* Allow space for 64bit int. */ - /* generate patches for all array elements that exist in "from" and "to" */ - for (c = 0, from = from->child, to = to->child; from && to; from = from->next, to = to->next, c++) - { - /* check if conversion to unsigned long is valid - * This should be eliminated at compile time by dead code elimination - * if size_t is an alias of unsigned long, or if it is bigger */ - if (c > ULONG_MAX) - { - free(newpath); - return; - } - sprintf((char*)newpath, "%s/%lu", path, (unsigned long)c); /* path of the current array element */ - cJSONUtils_CompareToPatch(patches, newpath, from, to); - } - /* remove leftover elements from 'from' that are not in 'to' */ - for (; from; from = from->next, c++) - { - /* check if conversion to unsigned long is valid - * This should be eliminated at compile time by dead code elimination - * if size_t is an alias of unsigned long, or if it is bigger */ - if (c > ULONG_MAX) - { - free(newpath); - return; - } - sprintf((char*)newpath, "%lu", (unsigned long)c); - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, newpath, 0); - } - /* add new elements in 'to' that were not in 'from' */ - for (; to; to = to->next, c++) - { - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (const unsigned char*)"-", to); - } - free(newpath); - return; - } - - case cJSON_Object: - { - cJSON *a = NULL; - cJSON *b = NULL; - cJSONUtils_SortObject(from); - cJSONUtils_SortObject(to); - - a = from->child; - b = to->child; - /* for all object values in the object with more of them */ - while (a || b) - { - int diff = (!a) ? 1 : ((!b) ? -1 : cJSONUtils_strcasecmp((unsigned char*)a->string, (unsigned char*)b->string)); - if (!diff) - { - /* both object keys are the same */ - unsigned char *newpath = (unsigned char*)malloc(strlen((const char*)path) + cJSONUtils_PointerEncodedstrlen((unsigned char*)a->string) + 2); - cJSONUtils_PointerEncodedstrcpy(newpath + sprintf((char*)newpath, "%s/", path), (unsigned char*)a->string); - /* create a patch for the element */ - cJSONUtils_CompareToPatch(patches, newpath, a, b); - free(newpath); - a = a->next; - b = b->next; - } - else if (diff < 0) - { - /* object element doesn't exist in 'to' --> remove it */ - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"remove", path, (unsigned char*)a->string, 0); - a = a->next; - } - else - { - /* object element doesn't exist in 'from' --> add it */ - cJSONUtils_GeneratePatch(patches, (const unsigned char*)"add", path, (unsigned char*)b->string, b); - b = b->next; - } - } - return; - } - - default: - break; - } -} - -CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to) -{ - cJSON *patches = cJSON_CreateArray(); - cJSONUtils_CompareToPatch(patches, (const unsigned char*)"", from, to); - - return patches; -} - -/* sort lists using mergesort */ -static cJSON *cJSONUtils_SortList(cJSON *list) -{ - cJSON *first = list; - cJSON *second = list; - cJSON *ptr = list; - - if (!list || !list->next) - { - /* One entry is sorted already. */ - return list; - } - - while (ptr && ptr->next && (cJSONUtils_strcasecmp((unsigned char*)ptr->string, (unsigned char*)ptr->next->string) < 0)) - { - /* Test for list sorted. */ - ptr = ptr->next; - } - if (!ptr || !ptr->next) - { - /* Leave sorted lists unmodified. */ - return list; - } - - /* reset ptr to the beginning */ - ptr = list; - while (ptr) - { - /* Walk two pointers to find the middle. */ - second = second->next; - ptr = ptr->next; - /* advances ptr two steps at a time */ - if (ptr) - { - ptr = ptr->next; - } - } - if (second && second->prev) - { - /* Split the lists */ - second->prev->next = NULL; - } - - /* Recursively sort the sub-lists. */ - first = cJSONUtils_SortList(first); - second = cJSONUtils_SortList(second); - list = ptr = NULL; - - while (first && second) /* Merge the sub-lists */ - { - if (cJSONUtils_strcasecmp((unsigned char*)first->string, (unsigned char*)second->string) < 0) - { - if (!list) - { - /* start merged list with the first element of the first list */ - list = ptr = first; - } - else - { - /* add first element of first list to merged list */ - ptr->next = first; - first->prev = ptr; - ptr = first; - } - first = first->next; - } - else - { - if (!list) - { - /* start merged list with the first element of the second list */ - list = ptr = second; - } - else - { - /* add first element of second list to merged list */ - ptr->next = second; - second->prev = ptr; - ptr = second; - } - second = second->next; - } - } - if (first) - { - /* Append rest of first list. */ - if (!list) - { - return first; - } - ptr->next = first; - first->prev = ptr; - } - if (second) - { - /* Append rest of second list */ - if (!list) - { - return second; - } - ptr->next = second; - second->prev = ptr; - } - - return list; -} - -CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object) -{ - object->child = cJSONUtils_SortList(object->child); -} - -CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch) -{ - if (!patch || ((patch->type & 0xFF) != cJSON_Object)) - { - /* scalar value, array or NULL, just duplicate */ - cJSON_Delete(target); - return cJSON_Duplicate(patch, 1); - } - - if (!target || ((target->type & 0xFF) != cJSON_Object)) - { - cJSON_Delete(target); - target = cJSON_CreateObject(); - } - - patch = patch->child; - while (patch) - { - if ((patch->type & 0xFF) == cJSON_NULL) - { - /* NULL is the indicator to remove a value, see RFC7396 */ - cJSON_DeleteItemFromObject(target, patch->string); - } - else - { - cJSON *replaceme = cJSON_DetachItemFromObject(target, patch->string); - cJSON_AddItemToObject(target, patch->string, cJSONUtils_MergePatch(replaceme, patch)); - } - patch = patch->next; - } - return target; -} - -CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to) -{ - cJSON *patch = NULL; - if (!to) - { - /* patch to delete everything */ - return cJSON_CreateNull(); - } - if (((to->type & 0xFF) != cJSON_Object) || !from || ((from->type & 0xFF) != cJSON_Object)) - { - return cJSON_Duplicate(to, 1); - } - - cJSONUtils_SortObject(from); - cJSONUtils_SortObject(to); - - from = from->child; - to = to->child; - patch = cJSON_CreateObject(); - while (from || to) - { - int compare = from ? (to ? strcmp(from->string, to->string) : -1) : 1; - if (compare < 0) - { - /* from has a value that to doesn't have -> remove */ - cJSON_AddItemToObject(patch, from->string, cJSON_CreateNull()); - from = from->next; - } - else if (compare > 0) - { - /* to has a value that from doesn't have -> add to patch */ - cJSON_AddItemToObject(patch, to->string, cJSON_Duplicate(to, 1)); - to = to->next; - } - else - { - /* object key exists in both objects */ - if (cJSONUtils_Compare(from, to)) - { - /* not identical --> generate a patch */ - cJSON_AddItemToObject(patch, to->string, cJSONUtils_GenerateMergePatch(from, to)); - } - /* next key in the object */ - from = from->next; - to = to->next; - } - } - if (!patch->child) - { - cJSON_Delete(patch); - return NULL; - } - - return patch; -} diff --git a/libs/libks/src/include/ks.h b/libs/libks/src/include/ks.h deleted file mode 100644 index 4965a50a95..0000000000 --- a/libs/libks/src/include/ks.h +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_H_ -#define _KS_H_ - -#ifdef __cplusplus -#define KS_BEGIN_EXTERN_C extern "C" { -#define KS_END_EXTERN_C } -#else -#define KS_BEGIN_EXTERN_C -#define KS_END_EXTERN_C -#endif - -#include -#include - -KS_BEGIN_EXTERN_C - -#define BUF_CHUNK 65536 * 50 -#define BUF_START 65536 * 100 - - -/*! - \brief Test for NULL or zero length string - \param s the string to test - \return true value if the string is NULL or zero length -*/ -_Check_return_ static __inline int _zstr(_In_opt_z_ const char *s) -{ - return !s || *s == '\0'; -} -#ifdef _PREFAST_ -#define zstr(x) (_zstr(x) ? 1 : __analysis_assume(x),0) -#else -#define zstr(x) _zstr(x) -#endif -#define ks_strlen_zero(x) zstr(x) -#define ks_strlen_zero_buf(x) zstr_buf(x) -#define zstr_buf(s) (*(s) == '\0') - -#define ks_set_string(_x, _y) ks_copy_string(_x, _y, sizeof(_x)) -#define ks_safe_free(_x) if (_x) free(_x); _x = NULL -#define end_of(_s) *(*_s == '\0' ? _s : _s + strlen(_s) - 1) -#define ks_recv(_h) ks_recv_event(_h, 0, NULL) -#define ks_recv_timed(_h, _ms) ks_recv_event_timed(_h, _ms, 0, NULL) - -/* -* bitflag tools -*/ -#define BIT_FLAG(x) (1 << (x)) -#define BIT_SET(v,f) ((v) |= (f)) -#define BIT_CLEAR(v,f) ((v) &= ~(f)) -#define BIT_IS_SET(v,f) ((v) & (f)) -#define BIT_TOGGLE(v,f) ((v) ^= (f)) - -KS_DECLARE(ks_status_t) ks_init(void); -KS_DECLARE(ks_status_t) ks_shutdown(void); -KS_DECLARE(ks_pool_t *) ks_global_pool(void); -KS_DECLARE(int) ks_vasprintf(char **ret, const char *fmt, va_list ap); - -//KS_DECLARE_DATA extern ks_logger_t ks_logger; -KS_DECLARE(void) ks_log(const char *file, const char *func, int line, int level, const char *fmt, ...); - -/*! Sets the logger for libks. Default is the null_logger */ -KS_DECLARE(void) ks_global_set_logger(ks_logger_t logger); -/*! Sets the default log level for libks */ -KS_DECLARE(void) ks_global_set_default_logger(int level); -/*! Sets the default log prefix for libks */ -KS_DECLARE(void) ks_global_set_default_logger_prefix(ks_log_prefix_t prefix); - -KS_DECLARE(size_t) ks_url_encode(const char *url, char *buf, size_t len); -KS_DECLARE(char *) ks_url_decode(char *s); -KS_DECLARE(const char *) ks_stristr(const char *instr, const char *str); -KS_DECLARE(int) ks_toupper(int c); -KS_DECLARE(int) ks_tolower(int c); -KS_DECLARE(char *) ks_copy_string(char *from_str, const char *to_str, ks_size_t from_str_len); -KS_DECLARE(int) ks_snprintf(char *buffer, size_t count, const char *fmt, ...); -KS_DECLARE(unsigned int) ks_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen); -KS_DECLARE(unsigned int) ks_separate_string(char *buf, char delim, char **array, unsigned int arraylen); - -#define ks_inet_pton inet_pton - -KS_DECLARE(int) ks_cpu_count(void); - static __inline__ int ks_safe_strcasecmp(const char *s1, const char *s2) { - if (!(s1 && s2)) { - return 1; - } - - return strcasecmp(s1, s2); - } - - -KS_DECLARE(void) ks_random_string(char *buf, uint16_t len, char *set); - -#define ks_str_nil(s) (s ? s : "") - -#include "ks_pool.h" -#include "ks_printf.h" -#include "ks_json.h" -#include "ks_threadmutex.h" -#include "ks_thread_pool.h" -#include "ks_hash.h" -#include "ks_config.h" -#include "ks_q.h" -#include "ks_buffer.h" -#include "ks_time.h" -#include "ks_socket.h" -#include "ks_dso.h" -#include "simclist.h" -#include "ks_ssl.h" -#include "kws.h" -#include "ks_rng.h" -#include "ks_acl.h" -#include "ks_base64.h" -#include "ks_time.h" -#include "ks_sb.h" - -KS_END_EXTERN_C - -#endif /* defined(_KS_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_acl.h b/libs/libks/src/include/ks_acl.h deleted file mode 100644 index c75612f77c..0000000000 --- a/libs/libks/src/include/ks_acl.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_ACL_H_ -#define _KS_ACL_H_ - -KS_BEGIN_EXTERN_C - -typedef union{ - uint32_t v4; - struct in6_addr v6; -} ks_ip_t; - - -#define switch_network_list_validate_ip(_list, _ip) switch_network_list_validate_ip_token(_list, _ip, NULL); - -#define switch_test_subnet(_ip, _net, _mask) (_mask ? ((_net & _mask) == (_ip & _mask)) : _net ? _net == _ip : 1) - - -KS_DECLARE(int) ks_parse_cidr(const char *string, ks_ip_t *ip, ks_ip_t *mask, uint32_t *bitp); -KS_DECLARE(ks_status_t) ks_network_list_create(ks_network_list_t **list, const char *name, ks_bool_t default_type, - ks_pool_t *pool); -KS_DECLARE(ks_status_t) ks_network_list_add_cidr_token(ks_network_list_t *list, const char *cidr_str, ks_bool_t ok, const char *token); -#define ks_network_list_add_cidr(_list, _cidr_str, _ok) ks_network_list_add_cidr_token(_list, _cidr_str, _ok, NULL) - -KS_DECLARE(char *) ks_network_ipv4_mapped_ipv6_addr(const char* ip_str); -KS_DECLARE(ks_status_t) ks_network_list_add_host_mask(ks_network_list_t *list, const char *host, const char *mask_str, ks_bool_t ok); -KS_DECLARE(ks_bool_t) ks_network_list_validate_ip_token(ks_network_list_t *list, uint32_t ip, const char **token); -KS_DECLARE(ks_bool_t) ks_network_list_validate_ip6_token(ks_network_list_t *list, ks_ip_t ip, const char **token); - -#define ks_network_list_validate_ip(_list, _ip) ks_network_list_validate_ip_token(_list, _ip, NULL); - -#define ks_test_subnet(_ip, _net, _mask) (_mask ? ((_net & _mask) == (_ip & _mask)) : _net ? _net == _ip : 1) - -KS_DECLARE(ks_bool_t) ks_check_network_list_ip_cidr(const char *ip_str, const char *cidr_str); -KS_DECLARE(ks_bool_t) ks_check_network_list_ip_token(const char *ip_str, ks_network_list_t *list, const char **token); -#define ks_check_network_list_ip(_i, _l) ks_check_network_list_ip_token(_i, _l, NULL) - -KS_END_EXTERN_C -#endif /* defined(_KS_ACL_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ - diff --git a/libs/libks/src/include/ks_base64.h b/libs/libks/src/include/ks_base64.h deleted file mode 100644 index 3c5eb81ace..0000000000 --- a/libs/libks/src/include/ks_base64.h +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2017 FreeSWITCH Solutions 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_BASE64_H__ -#define _KS_BASE64_H__ - -#include - -KS_DECLARE(ks_status_t) ks_b64_encode(unsigned char *in, ks_size_t ilen, unsigned char *out, ks_size_t olen); -KS_DECLARE(ks_size_t) ks_b64_decode(char *in, char *out, ks_size_t olen); - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_buffer.h b/libs/libks/src/include/ks_buffer.h deleted file mode 100644 index dc28ef7fbf..0000000000 --- a/libs/libks/src/include/ks_buffer.h +++ /dev/null @@ -1,152 +0,0 @@ -/* - * Copyright (c) 2010-2015, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 KS_BUFFER_H -#define KS_BUFFER_H - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -/** - * @defgroup ks_buffer Buffer Routines - * @ingroup buffer - * The purpose of this module is to make a plain buffering interface that can be used for read/write buffers - * throughout the application. - * @{ - */ -struct ks_buffer; -typedef struct ks_buffer ks_buffer_t; - -/*! \brief Allocate a new dynamic ks_buffer - * \param buffer returned pointer to the new buffer - * \param blocksize length to realloc by as data is added - * \param start_len ammount of memory to reserve initially - * \param max_len length the buffer is allowed to grow to - * \return status - */ -KS_DECLARE(ks_status_t) ks_buffer_create(ks_buffer_t **buffer, ks_size_t blocksize, ks_size_t start_len, ks_size_t max_len); - -/*! \brief Get the length of a ks_buffer_t - * \param buffer any buffer of type ks_buffer_t - * \return int size of the buffer. - */ -KS_DECLARE(ks_size_t) ks_buffer_len(ks_buffer_t *buffer); - -/*! \brief Get the freespace of a ks_buffer_t - * \param buffer any buffer of type ks_buffer_t - * \return int freespace in the buffer. - */ -KS_DECLARE(ks_size_t) ks_buffer_freespace(ks_buffer_t *buffer); - -/*! \brief Get the in use amount of a ks_buffer_t - * \param buffer any buffer of type ks_buffer_t - * \return int ammount of buffer curently in use - */ -KS_DECLARE(ks_size_t) ks_buffer_inuse(ks_buffer_t *buffer); - -/*! \brief Read data from a ks_buffer_t up to the ammount of datalen if it is available. Remove read data from buffer. - * \param buffer any buffer of type ks_buffer_t - * \param data pointer to the read data to be returned - * \param datalen amount of data to be returned - * \return int ammount of data actually read - */ -KS_DECLARE(ks_size_t) ks_buffer_read(ks_buffer_t *buffer, void *data, ks_size_t datalen); - -KS_DECLARE(ks_size_t) ks_buffer_read_packet(ks_buffer_t *buffer, void *data, ks_size_t maxlen); -KS_DECLARE(ks_size_t) ks_buffer_packet_count(ks_buffer_t *buffer); - -/*! \brief Read data endlessly from a ks_buffer_t - * \param buffer any buffer of type ks_buffer_t - * \param data pointer to the read data to be returned - * \param datalen amount of data to be returned - * \return int ammount of data actually read - * \note Once you have read all the data from the buffer it will loop around. - */ -KS_DECLARE(ks_size_t) ks_buffer_read_loop(ks_buffer_t *buffer, void *data, ks_size_t datalen); - -/*! \brief Assign a number of loops to read - * \param buffer any buffer of type ks_buffer_t - * \param loops the number of loops (-1 for infinite) - */ -KS_DECLARE(void) ks_buffer_set_loops(ks_buffer_t *buffer, int32_t loops); - -/*! \brief Write data into a ks_buffer_t up to the length of datalen - * \param buffer any buffer of type ks_buffer_t - * \param data pointer to the data to be written - * \param datalen amount of data to be written - * \return int amount of buffer used after the write, or 0 if no space available - */ -KS_DECLARE(ks_size_t) ks_buffer_write(ks_buffer_t *buffer, const void *data, ks_size_t datalen); - -/*! \brief Remove data from the buffer - * \param buffer any buffer of type ks_buffer_t - * \param datalen amount of data to be removed - * \return int size of buffer, or 0 if unable to toss that much data - */ -KS_DECLARE(ks_size_t) ks_buffer_toss(ks_buffer_t *buffer, ks_size_t datalen); - -/*! \brief Remove all data from the buffer - * \param buffer any buffer of type ks_buffer_t - */ -KS_DECLARE(void) ks_buffer_zero(ks_buffer_t *buffer); - -/*! \brief Destroy the buffer - * \param buffer buffer to destroy - * \note only neccessary on dynamic buffers (noop on pooled ones) - */ -KS_DECLARE(void) ks_buffer_destroy(ks_buffer_t **buffer); - -/*! \brief Seek to offset from the beginning of the buffer - * \param buffer buffer to seek - * \param datalen offset in bytes - * \return new position - */ -KS_DECLARE(ks_size_t) ks_buffer_seek(ks_buffer_t *buffer, ks_size_t datalen); - -/** @} */ - -KS_DECLARE(ks_size_t) ks_buffer_zwrite(ks_buffer_t *buffer, const void *data, ks_size_t datalen); - -KS_END_EXTERN_C -#endif -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_cJSON.h b/libs/libks/src/include/ks_cJSON.h deleted file mode 100644 index 2909b713d6..0000000000 --- a/libs/libks/src/include/ks_cJSON.h +++ /dev/null @@ -1,239 +0,0 @@ -/* - Copyright (c) 2009 Dave Gamble - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ - -#ifndef cJSON__h -#define cJSON__h - -#ifdef KS_EXPORTS -#ifndef CJSON_EXPORT_SYMBOLS -#define CJSON_EXPORT_SYMBOLS 1 -#endif -#else -#ifndef CJSON_HIDE_SYMBOLS -#define CJSON_HIDE_SYMBOLS 1 -#endif -#endif - -#ifdef KS_API_VISIBILITY -#ifndef CJSON_API_VISIBILITY -#define CJSON_API_VISIBILITY 1 -#endif -#endif - -#ifdef __cplusplus -extern "C" -{ -#endif - -/* project version */ -#define CJSON_VERSION_MAJOR 1 -#define CJSON_VERSION_MINOR 3 -#define CJSON_VERSION_PATCH 0 - -#include - -/* cJSON Types: */ -#define cJSON_Invalid (0) -#define cJSON_False (1 << 0) -#define cJSON_True (1 << 1) -#define cJSON_NULL (1 << 2) -#define cJSON_Number (1 << 3) -#define cJSON_String (1 << 4) -#define cJSON_Array (1 << 5) -#define cJSON_Object (1 << 6) -#define cJSON_Raw (1 << 7) /* raw json */ - -#define cJSON_IsReference 256 -#define cJSON_StringIsConst 512 - -/* The cJSON structure: */ -typedef struct cJSON -{ - /* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */ - struct cJSON *next; - struct cJSON *prev; - /* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */ - struct cJSON *child; - - /* The type of the item, as above. */ - int type; - - /* The item's string, if type==cJSON_String and type == cJSON_Raw */ - char *valuestring; - /* The item's number, if type==cJSON_Number */ - int valueint; - /* The item's number, if type==cJSON_Number */ - double valuedouble; - - /* The item's name string, if this item is the child of, or is in the list of subitems of an object. */ - char *string; -} cJSON; - -typedef struct cJSON_Hooks -{ - void *(*malloc_fn)(size_t sz); - void (*free_fn)(void *ptr); -} cJSON_Hooks; - -#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -#define __WINDOWS__ -#endif -#ifdef __WINDOWS__ - -/* When compiling for windows, we specify a specific calling convention to avoid issues where we are being called from a project with a different default calling convention. For windows you have 2 define options: - -CJSON_HIDE_SYMBOLS - Define this in the case where you don't want to ever dllexport symbols -CJSON_EXPORT_SYMBOLS - Define this on library build when you want to dllexport symbols - -For *nix builds that support visibility attribute, you can define similar behavior by - -setting default visibility to hidden by adding --fvisibility=hidden (for gcc) -or --xldscope=hidden (for sun cc) -to CFLAGS - -then using the CJSON_API_VISIBILITY flag to "export" the same symbols the way CJSON_EXPORT_SYMBOLS does - -*/ - -#if defined(CJSON_HIDE_SYMBOLS) -#define CJSON_PUBLIC(type) type __stdcall -#elif defined(CJSON_EXPORT_SYMBOLS) -#define CJSON_PUBLIC(type) __declspec(dllexport) type __stdcall -#else -#define CJSON_PUBLIC(type) __declspec(dllimport) type __stdcall -#endif -#else /* !WIN32 */ -#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(CJSON_API_VISIBILITY) -#define CJSON_PUBLIC(type) __attribute__((visibility("default"))) type -#else -#define CJSON_PUBLIC(type) type -#endif -#endif - -/* returns the version of cJSON as a string */ -CJSON_PUBLIC(const char*) cJSON_Version(void); - -/* Supply malloc, realloc and free functions to cJSON */ -CJSON_PUBLIC(void) cJSON_InitHooks(cJSON_Hooks* hooks); - - -/* Supply a block of JSON, and this returns a cJSON object you can interrogate. Call cJSON_Delete when finished. */ -CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value); -/* Render a cJSON entity to text for transfer/storage. Free the char* when finished. */ -CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item); -/* Render a cJSON entity to text for transfer/storage without any formatting. Free the char* when finished. */ -CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item); -/* Render a cJSON entity to text using a buffered strategy. prebuffer is a guess at the final size. guessing well reduces reallocation. fmt=0 gives unformatted, =1 gives formatted */ -CJSON_PUBLIC(char *) cJSON_PrintBuffered(const cJSON *item, int prebuffer, int fmt); -/* Render a cJSON entity to text using a buffer already allocated in memory with length buf_len. Returns 1 on success and 0 on failure. */ -CJSON_PUBLIC(int) cJSON_PrintPreallocated(cJSON *item, char *buf, const int len, const int fmt); -/* Delete a cJSON entity and all subentities. */ -CJSON_PUBLIC(void) cJSON_Delete(cJSON *c); - -/* Returns the number of items in an array (or object). */ -CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array); -/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */ -CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int item); -/* Get item "string" from object. Case insensitive. */ -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON *object, const char *string); -CJSON_PUBLIC(cJSON *) cJSON_GetObjectItemCaseSensitive(const cJSON * const object, const char * const string); -CJSON_PUBLIC(int) cJSON_HasObjectItem(const cJSON *object, const char *string); -/* For analysing failed parses. This returns a pointer to the parse error. You'll probably need to look a few chars back to make sense of it. Defined when cJSON_Parse() returns 0. 0 when cJSON_Parse() succeeds. */ -CJSON_PUBLIC(const char *) cJSON_GetErrorPtr(void); - -/* These calls create a cJSON item of the appropriate type. */ -CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateBool(int b); -CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num); -CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string); -/* raw json */ -CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw); -CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void); -CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void); - -/* These utilities create an Array of count items. */ -CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count); -CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count); - -/* Append item to the specified array/object. */ -CJSON_PUBLIC(void) cJSON_AddItemToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(void) cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); -/* Use this when string is definitely const (i.e. a literal, or as good as), and will definitely survive the cJSON object. - * WARNING: When this function was used, make sure to always check that (item->type & cJSON_StringIsConst) is zero before - * writing to `item->string` */ -CJSON_PUBLIC(void) cJSON_AddItemToObjectCS(cJSON *object, const char *string, cJSON *item); -/* Append reference to item to the specified array/object. Use this when you want to add an existing cJSON to a new cJSON, but don't want to corrupt your existing cJSON. */ -CJSON_PUBLIC(void) cJSON_AddItemReferenceToArray(cJSON *array, cJSON *item); -CJSON_PUBLIC(void) cJSON_AddItemReferenceToObject(cJSON *object, const char *string, cJSON *item); - -/* Remove/Detatch items from Arrays/Objects. */ -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(void) cJSON_DeleteItemFromArray(cJSON *array, int which); -CJSON_PUBLIC(cJSON *) cJSON_DetachItemFromObject(cJSON *object, const char *string); -CJSON_PUBLIC(void) cJSON_DeleteItemFromObject(cJSON *object, const char *string); - -/* Update array items. */ -CJSON_PUBLIC(void) cJSON_InsertItemInArray(cJSON *array, int which, cJSON *newitem); /* Shifts pre-existing items to the right. */ -CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem); -CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem); - -/* Duplicate a cJSON item */ -CJSON_PUBLIC(cJSON *) cJSON_Duplicate(const cJSON *item, int recurse); -/* Duplicate will create a new, identical cJSON item to the one you pass, in new memory that will -need to be released. With recurse!=0, it will duplicate any children connected to the item. -The item->next and ->prev pointers are always zero on return from Duplicate. */ - -/* ParseWithOpts allows you to require (and check) that the JSON is null terminated, and to retrieve the pointer to the final byte parsed. */ -/* If you supply a ptr in return_parse_end and parsing fails, then return_parse_end will contain a pointer to the error. If not, then cJSON_GetErrorPtr() does the job. */ -CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, int require_null_terminated); - -CJSON_PUBLIC(void) cJSON_Minify(char *json); - -/* Macros for creating things quickly. */ -#define cJSON_AddNullToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateNull()) -#define cJSON_AddTrueToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateTrue()) -#define cJSON_AddFalseToObject(object,name) cJSON_AddItemToObject(object, name, cJSON_CreateFalse()) -#define cJSON_AddBoolToObject(object,name,b) cJSON_AddItemToObject(object, name, cJSON_CreateBool(b)) -#define cJSON_AddNumberToObject(object,name,n) cJSON_AddItemToObject(object, name, cJSON_CreateNumber(n)) -#define cJSON_AddStringToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateString(s)) -#define cJSON_AddRawToObject(object,name,s) cJSON_AddItemToObject(object, name, cJSON_CreateRaw(s)) - -/* When assigning an integer value, it needs to be propagated to valuedouble too. */ -#define cJSON_SetIntValue(object, number) ((object) ? (object)->valueint = (object)->valuedouble = (number) : (number)) -/* helper for the cJSON_SetNumberValue macro */ -CJSON_PUBLIC(double) cJSON_SetNumberHelper(cJSON *object, double number); -#define cJSON_SetNumberValue(object, number) ((object != NULL) ? cJSON_SetNumberHelper(object, (double)number) : (number)) - -/* Macro for iterating over an array */ -#define cJSON_ArrayForEach(element, array) for(element = (array != NULL) ? (array)->child : NULL; element != NULL; element = element->next) - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/libks/src/include/ks_cJSON_Utils.h b/libs/libks/src/include/ks_cJSON_Utils.h deleted file mode 100644 index 58a9b256da..0000000000 --- a/libs/libks/src/include/ks_cJSON_Utils.h +++ /dev/null @@ -1,44 +0,0 @@ -#include "ks_cJSON.h" - -/* Implement RFC6901 (https://tools.ietf.org/html/rfc6901) JSON Pointer spec. */ -CJSON_PUBLIC(cJSON *) cJSONUtils_GetPointer(cJSON *object, const char *pointer); - -/* Implement RFC6902 (https://tools.ietf.org/html/rfc6902) JSON Patch spec. */ -CJSON_PUBLIC(cJSON *) cJSONUtils_GeneratePatches(cJSON *from, cJSON *to); -/* Utility for generating patch array entries. */ -CJSON_PUBLIC(void) cJSONUtils_AddPatchToArray(cJSON *array, const char *op, const char *path, cJSON *val); -/* Returns 0 for success. */ -CJSON_PUBLIC(int) cJSONUtils_ApplyPatches(cJSON *object, cJSON *patches); - -/* -// Note that ApplyPatches is NOT atomic on failure. To implement an atomic ApplyPatches, use: -//int cJSONUtils_AtomicApplyPatches(cJSON **object, cJSON *patches) -//{ -// cJSON *modme = cJSON_Duplicate(*object, 1); -// int error = cJSONUtils_ApplyPatches(modme, patches); -// if (!error) -// { -// cJSON_Delete(*object); -// *object = modme; -// } -// else -// { -// cJSON_Delete(modme); -// } -// -// return error; -//} -// Code not added to library since this strategy is a LOT slower. -*/ - -/* Implement RFC7386 (https://tools.ietf.org/html/rfc7396) JSON Merge Patch spec. */ -/* target will be modified by patch. return value is new ptr for target. */ -CJSON_PUBLIC(cJSON *) cJSONUtils_MergePatch(cJSON *target, cJSON *patch); -/* generates a patch to move from -> to */ -CJSON_PUBLIC(cJSON *) cJSONUtils_GenerateMergePatch(cJSON *from, cJSON *to); - -/* Given a root object and a target object, construct a pointer from one to the other. */ -CJSON_PUBLIC(char *) cJSONUtils_FindPointerFromObjectTo(cJSON *object, cJSON *target); - -/* Sorts the members of the object into alphabetical order. */ -CJSON_PUBLIC(void) cJSONUtils_SortObject(cJSON *object); diff --git a/libs/libks/src/include/ks_config.h b/libs/libks/src/include/ks_config.h deleted file mode 100644 index bdbb9cea98..0000000000 --- a/libs/libks/src/include/ks_config.h +++ /dev/null @@ -1,170 +0,0 @@ -/* - * Copyright (c) 2007-2015, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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. - */ - -/** - * @defgroup config Config File Parser - * @ingroup config - * This module implements a basic interface and file format parser - * - *
- *
- * EXAMPLE 
- * 
- * [category1]
- * var1 => val1
- * var2 => val2
- * \# lines that begin with \# are comments
- * \#var3 => val3
- * 
- * @{ - */ - -#ifndef KS_CONFIG_H -#define KS_CONFIG_H - -KS_BEGIN_EXTERN_C - -#include "ks.h" - -#define KS_URL_SEPARATOR "://" - -#ifdef WIN32 -#define KS_PATH_SEPARATOR "\\" -#ifndef KS_CONFIG_DIR -#define KS_CONFIG_DIR "c:\\openks" -#endif -#define ks_is_file_path(file) (*(file +1) == ':' || *file == '/' || strstr(file, SWITCH_URL_SEPARATOR)) -#else -#define KS_PATH_SEPARATOR "/" -#ifndef KS_CONFIG_DIR -#define KS_CONFIG_DIR "/etc/openks" -#endif -#define ks_is_file_path(file) ((*file == '/') || strstr(file, SWITCH_URL_SEPARATOR)) -#endif - -/*! - \brief Evaluate the truthfullness of a string expression - \param expr a string expression - \return true or false -*/ -#define ks_true(expr)\ -(expr && ( !strcasecmp(expr, "yes") ||\ -!strcasecmp(expr, "on") ||\ -!strcasecmp(expr, "true") ||\ -!strcasecmp(expr, "enabled") ||\ -!strcasecmp(expr, "active") ||\ -!strcasecmp(expr, "allow") ||\ -atoi(expr))) ? 1 : 0 - -/*! - \brief Evaluate the falsefullness of a string expression - \param expr a string expression - \return true or false -*/ -#define ks_false(expr)\ -(expr && ( !strcasecmp(expr, "no") ||\ -!strcasecmp(expr, "off") ||\ -!strcasecmp(expr, "false") ||\ -!strcasecmp(expr, "disabled") ||\ -!strcasecmp(expr, "inactive") ||\ -!strcasecmp(expr, "disallow") ||\ -!atoi(expr))) ? 1 : 0 - -typedef struct ks_config ks_config_t; - -/*! \brief A simple file handle representing an open configuration file **/ - struct ks_config { - /*! FILE stream buffer to the opened file */ - FILE *file; - /*! path to the file */ - char path[512]; - /*! current category */ - char category[256]; - /*! current section */ - char section[256]; - /*! buffer of current line being read */ - char buf[1024]; - /*! current line number in file */ - int lineno; - /*! current category number in file */ - int catno; - /*! current section number in file */ - int sectno; - - int lockto; - }; - -/*! - \brief Open a configuration file - \param cfg (ks_config_t *) config handle to use - \param file_path path to the file - \return 1 (true) on success 0 (false) on failure -*/ - KS_DECLARE(int) ks_config_open_file(ks_config_t *cfg, const char *file_path); - -/*! - \brief Close a previously opened configuration file - \param cfg (ks_config_t *) config handle to use -*/ - KS_DECLARE(void) ks_config_close_file(ks_config_t *cfg); - -/*! - \brief Retrieve next name/value pair from configuration file - \param cfg (ks_config_t *) config handle to use - \param var pointer to aim at the new variable name - \param val pointer to aim at the new value -*/ - KS_DECLARE(int) ks_config_next_pair(ks_config_t *cfg, char **var, char **val); - -/*! - \brief Retrieve the CAS bits from a configuration string value - \param strvalue pointer to the configuration string value (expected to be in format whatever:xxxx) - \param outbits pointer to aim at the CAS bits -*/ - KS_DECLARE(int) ks_config_get_cas_bits(char *strvalue, unsigned char *outbits); - - -/** @} */ - -KS_END_EXTERN_C -#endif /* defined(KS_CONFIG_H) */ -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_dso.h b/libs/libks/src/include/ks_dso.h deleted file mode 100755 index 35c9763872..0000000000 --- a/libs/libks/src/include/ks_dso.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Cross Platform dso/dll load abstraction - * Copyright(C) 2008 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - -#include "ks.h" - -#ifndef _KS_DSO_H -#define _KS_DSO_H - -KS_BEGIN_EXTERN_C - -typedef void (*ks_func_ptr_t) (void); -typedef void * ks_dso_lib_t; - -KS_DECLARE(ks_status_t) ks_dso_destroy(ks_dso_lib_t *lib); -KS_DECLARE(ks_dso_lib_t) ks_dso_open(const char *path, char **err); -KS_DECLARE(void *) ks_dso_func_sym(ks_dso_lib_t lib, const char *sym, char **err); -KS_DECLARE(char *) ks_build_dso_path(const char *name, char *path, ks_size_t len); - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ - diff --git a/libs/libks/src/include/ks_hash.h b/libs/libks/src/include/ks_hash.h deleted file mode 100644 index 5651b28efd..0000000000 --- a/libs/libks/src/include/ks_hash.h +++ /dev/null @@ -1,722 +0,0 @@ -/* - * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application - * - * ks_hash.h -- Ks_Hash - * - */ - - -/* ks_hash.h Copyright (C) 2002 Christopher Clark */ - -#ifndef __KS_HASH_CWC22_H__ -#define __KS_HASH_CWC22_H__ - -#ifdef _MSC_VER -#ifndef __inline__ -#define __inline__ __inline -#endif -#endif - -#include "ks.h" - -#ifdef __cplusplus -extern "C" { -#endif - -typedef struct ks_hash ks_hash_t; -typedef struct ks_hash_iterator ks_hash_iterator_t; - -typedef enum { - KS_UNLOCKED, - KS_READLOCKED -} ks_locked_t; - - -/* Example of use: - * - * ks_hash_t *h; - * struct some_key *k; - * struct some_value *v; - * - * static unsigned int hash_from_key_fn( void *k ); - * static int keys_equal_fn ( void *key1, void *key2 ); - * - * h = ks_hash_create(16, hash_from_key_fn, keys_equal_fn); - * k = (struct some_key *) malloc(sizeof(struct some_key)); - * v = (struct some_value *) malloc(sizeof(struct some_value)); - * - * (initialise k and v to suitable values) - * - * if (! ks_hash_insert(h,k,v) ) - * { exit(-1); } - * - * if (NULL == (found = ks_hash_search(h,k) )) - * { printf("not found!"); } - * - * if (NULL == (found = ks_hash_remove(h,k) )) - * { printf("Not found\n"); } - * - */ - -/* Macros may be used to define type-safe(r) ks_hash access functions, with - * methods specialized to take known key and value types as parameters. - * - * Example: - * - * Insert this at the start of your file: - * - * DEFINE_KS_HASH_INSERT(insert_some, struct some_key, struct some_value); - * DEFINE_KS_HASH_SEARCH(search_some, struct some_key, struct some_value); - * DEFINE_KS_HASH_REMOVE(remove_some, struct some_key, struct some_value); - * - * This defines the functions 'insert_some', 'search_some' and 'remove_some'. - * These operate just like ks_hash_insert etc., with the same parameters, - * but their function signatures have 'struct some_key *' rather than - * 'void *', and hence can generate compile time errors if your program is - * supplying incorrect data as a key (and similarly for value). - * - * Note that the hash and key equality functions passed to ks_hash_create - * still take 'void *' parameters instead of 'some key *'. This shouldn't be - * a difficult issue as they're only defined and passed once, and the other - * functions will ensure that only valid keys are supplied to them. - * - * The cost for this checking is increased code size and runtime overhead - * - if performance is important, it may be worth switching back to the - * unsafe methods once your program has been debugged with the safe methods. - * This just requires switching to some simple alternative defines - eg: - * #define insert_some ks_hash_insert - * - */ - - -typedef enum { - KS_HASH_FLAG_MUTEX = 0, - KS_HASH_FLAG_FREE_KEY = (1 << 0), - KS_HASH_FLAG_FREE_VALUE = (1 << 1), - KS_HASH_FLAG_RWLOCK = (1 << 2), - KS_HASH_FLAG_DUP_CHECK = (1 << 3), - KS_HASH_FLAG_NOLOCK = (1 << 4) -} ks_hash_flag_t; - -#define KS_HASH_FREE_BOTH KS_HASH_FLAG_FREE_KEY | KS_HASH_FLAG_FREE_VALUE -#define KS_HASH_FLAG_NONE KS_HASH_FLAG_MUTEX - - -typedef enum { - KS_HASH_MODE_DEFAULT = 0, - KS_HASH_MODE_CASE_SENSITIVE, - KS_HASH_MODE_CASE_INSENSITIVE, - KS_HASH_MODE_INT, - KS_HASH_MODE_INT64, - KS_HASH_MODE_PTR, - KS_HASH_MODE_ARBITRARY -} ks_hash_mode_t; - - - -/***************************************************************************** - * ks_hash_create - - * @name ks_hash_create - * @param minsize minimum initial size of ks_hash - * @param hashfunction function for hashing keys - * @param key_eq_fn function for determining key equality - * @return newly created ks_hash or NULL on failure - */ - -KS_DECLARE(ks_status_t) -ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize, - unsigned int (*hashfunction) (void*), - int (*key_eq_fn) (void*,void*), ks_hash_mode_t mode, ks_hash_flag_t flags, ks_hash_destructor_t destructor, ks_pool_t *pool); - -/***************************************************************************** - * ks_hash_insert - - * @name ks_hash_insert - * @param h the ks_hash to insert into - * @param k the key - ks_hash claims ownership and will free on removal - * @param v the value - does not claim ownership - * @return KS_STATUS_SUCCESS for successful insertion - * - * This function will cause the table to expand if the insertion would take - * the ratio of entries to table size over the maximum load factor. - * - * This function does not check for repeated insertions with a duplicate key. - * The value returned when using a duplicate key is undefined -- when - * the ks_hash changes size, the order of retrieval of duplicate key - * entries is reversed. - * If in doubt, remove before insert. - */ - - -KS_DECLARE(ks_status_t) ks_hash_insert_ex(ks_hash_t *h, void *k, void *v, ks_hash_flag_t flags, ks_hash_destructor_t destructor); -#define ks_hash_insert(_h, _k, _v) ks_hash_insert_ex(_h, _k, _v, 0, NULL) - -#define DEFINE_KS_HASH_INSERT(fnname, keytype, valuetype) \ - int fnname (ks_hash_t *h, keytype *k, valuetype *v) \ - { \ - return ks_hash_insert(h,k,v); \ - } - - -KS_DECLARE(void) ks_hash_set_flags(ks_hash_t *h, ks_hash_flag_t flags); -KS_DECLARE(void) ks_hash_set_keysize(ks_hash_t *h, ks_size_t keysize); -KS_DECLARE(void) ks_hash_set_destructor(ks_hash_t *h, ks_hash_destructor_t destructor); - -/***************************************************************************** - * ks_hash_search - - * @name ks_hash_search - * @param h the ks_hash to search - * @param k the key to search for - does not claim ownership - * @return the value associated with the key, or NULL if none found - */ - -KS_DECLARE(void *) -ks_hash_search(ks_hash_t *h, void *k, ks_locked_t locked); - -#define DEFINE_KS_HASH_SEARCH(fnname, keytype, valuetype) \ - valuetype * fnname (ks_hash_t *h, keytype *k) \ - { \ - return (valuetype *) (ks_hash_search(h,k)); \ - } - -/***************************************************************************** - * ks_hash_remove - - * @name ks_hash_remove - * @param h the ks_hash to remove the item from - * @param k the key to search for - does not claim ownership - * @return the value associated with the key, or NULL if none found - */ - -KS_DECLARE(void *) /* returns value */ -ks_hash_remove(ks_hash_t *h, void *k); - -#define DEFINE_KS_HASH_REMOVE(fnname, keytype, valuetype) \ - valuetype * fnname (ks_hash_t *h, keytype *k) \ - { \ - return (valuetype *) (ks_hash_remove(h,k)); \ - } - - -/***************************************************************************** - * ks_hash_count - - * @name ks_hash_count - * @param h the ks_hash - * @return the number of items stored in the ks_hash - */ -KS_DECLARE(unsigned int) -ks_hash_count(ks_hash_t *h); - -/***************************************************************************** - * ks_hash_destroy - - * @name ks_hash_destroy - * @param h the ks_hash - * @param free_values whether to call 'free' on the remaining values - */ - -KS_DECLARE(void) -ks_hash_destroy(ks_hash_t **h); - -KS_DECLARE(ks_hash_iterator_t*) ks_hash_first(ks_hash_t *h, ks_locked_t locked); -KS_DECLARE(void) ks_hash_last(ks_hash_iterator_t **iP); -KS_DECLARE(ks_hash_iterator_t*) ks_hash_next(ks_hash_iterator_t **iP); -KS_DECLARE(void) ks_hash_this(ks_hash_iterator_t *i, const void **key, ks_ssize_t *klen, void **val); -KS_DECLARE(void) ks_hash_this_val(ks_hash_iterator_t *i, void *val); -KS_DECLARE(ks_status_t) ks_hash_create(ks_hash_t **hp, ks_hash_mode_t mode, ks_hash_flag_t flags, ks_pool_t *pool); - -KS_DECLARE(void) ks_hash_write_lock(ks_hash_t *h); -KS_DECLARE(void) ks_hash_write_unlock(ks_hash_t *h); -KS_DECLARE(ks_status_t) ks_hash_read_lock(ks_hash_t *h); -KS_DECLARE(ks_status_t) ks_hash_read_unlock(ks_hash_t *h); - - -static __inline uint32_t ks_hash_default_int64(void *ky) -{ - int64_t key = *((int64_t *)ky); - key = (~key) + (key << 18); - key = key ^ (key >> 31); - key = key * 21; - key = key ^ (key >> 11); - key = key + (key << 6); - key = key ^ (key >> 22); - return (uint32_t) key; -} - -static __inline int ks_hash_equalkeys_int64(void *k1, void *k2) -{ - return *(uint64_t *)k1 == *(uint64_t *)k2; -} - -static __inline uint32_t ks_hash_default_int(void *ky) { - uint32_t x = *((uint32_t *)ky); - x = ((x >> 16) ^ x) * 0x45d9f3b; - x = ((x >> 16) ^ x) * 0x45d9f3b; - x = ((x >> 16) ^ x); - return x; -} - -static __inline int ks_hash_equalkeys_int(void *k1, void *k2) -{ - return *(uint32_t *)k1 == *(uint32_t *)k2; -} -#if 0 -} -#endif - -static __inline uint32_t ks_hash_default_ptr(void *ky) -{ -#ifdef KS_64BIT - return ks_hash_default_int64(ky); -#endif - return ks_hash_default_int(ky); -} - -static __inline int ks_hash_equalkeys_ptr(void *k1, void *k2) -{ -#ifdef KS_64BIT - return ks_hash_equalkeys_int64(k1, k2); -#endif - return ks_hash_equalkeys_int(k1, k2); -} - - -static __inline int ks_hash_equalkeys(void *k1, void *k2) -{ - return strcmp((char *) k1, (char *) k2) ? 0 : 1; -} - -static __inline int ks_hash_equalkeys_ci(void *k1, void *k2) -{ - return strcasecmp((char *) k1, (char *) k2) ? 0 : 1; -} - -static __inline uint32_t ks_hash_default(void *ky) -{ - unsigned char *str = (unsigned char *) ky; - uint32_t hash = 0; - int c; - - while ((c = *str)) { - str++; - hash = c + (hash << 6) + (hash << 16) - hash; - } - - return hash; -} - -static __inline uint32_t ks_hash_default_ci(void *ky) -{ - unsigned char *str = (unsigned char *) ky; - uint32_t hash = 0; - int c; - - while ((c = ks_tolower(*str))) { - str++; - hash = c + (hash << 6) + (hash << 16) - hash; - } - - return hash; -} - -#define hashsize(n) ((uint32_t)1<<(n)) -#define hashmask(n) (hashsize(n)-1) -#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) - -/* -------------------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. - -This is reversible, so any information in (a,b,c) before mix() is -still in (a,b,c) after mix(). - -If four pairs of (a,b,c) inputs are run through mix(), or through -mix() in reverse, there are at least 32 bits of the output that -are sometimes the same for one pair and different for another pair. -This was tested for: -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that -satisfy this are - 4 6 8 16 19 4 - 9 15 3 18 27 15 - 14 9 3 7 17 3 -Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing -for "differ" defined as + with a one-bit base and a two-bit delta. I -used http://burtleburtle.net/bob/hash/avalanche.html to choose -the operations, constants, and arrangements of the variables. - -This does not achieve avalanche. There are input bits of (a,b,c) -that fail to affect some output bits of (a,b,c), especially of a. The -most thoroughly mixed value is c, but it doesn't really even achieve -avalanche in c. - -This allows some parallelism. Read-after-writes are good at doubling -the number of bits affected, so the goal of mixing pulls in the opposite -direction as the goal of parallelism. I did what I could. Rotates -seem to cost as much as shifts on every machine I could lay my hands -on, and rotates are much kinder to the top and bottom bits, so I used -rotates. -------------------------------------------------------------------------------- -*/ -#define mix(a,b,c) \ -{ \ - a -= c; a ^= rot(c, 4); c += b; \ - b -= a; b ^= rot(a, 6); a += c; \ - c -= b; c ^= rot(b, 8); b += a; \ - a -= c; a ^= rot(c,16); c += b; \ - b -= a; b ^= rot(a,19); a += c; \ - c -= b; c ^= rot(b, 4); b += a; \ -} - -/* -------------------------------------------------------------------------------- -mix -- mix 3 32-bit values reversibly. - -This is reversible, so any information in (a,b,c) before mix() is -still in (a,b,c) after mix(). - -If four pairs of (a,b,c) inputs are run through mix(), or through -mix() in reverse, there are at least 32 bits of the output that -are sometimes the same for one pair and different for another pair. -This was tested for: -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that -satisfy this are - 4 6 8 16 19 4 - 9 15 3 18 27 15 - 14 9 3 7 17 3 -Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing -for "differ" defined as + with a one-bit base and a two-bit delta. I -used http://burtleburtle.net/bob/hash/avalanche.html to choose -the operations, constants, and arrangements of the variables. - -This does not achieve avalanche. There are input bits of (a,b,c) -that fail to affect some output bits of (a,b,c), especially of a. The -most thoroughly mixed value is c, but it doesn't really even achieve -avalanche in c. - -This allows some parallelism. Read-after-writes are good at doubling -the number of bits affected, so the goal of mixing pulls in the opposite -direction as the goal of parallelism. I did what I could. Rotates -seem to cost as much as shifts on every machine I could lay my hands -on, and rotates are much kinder to the top and bottom bits, so I used -rotates. -------------------------------------------------------------------------------- -*/ -#define mix(a,b,c) \ -{ \ - a -= c; a ^= rot(c, 4); c += b; \ - b -= a; b ^= rot(a, 6); a += c; \ - c -= b; c ^= rot(b, 8); b += a; \ - a -= c; a ^= rot(c,16); c += b; \ - b -= a; b ^= rot(a,19); a += c; \ - c -= b; c ^= rot(b, 4); b += a; \ -} - -/* -------------------------------------------------------------------------------- -final -- final mixing of 3 32-bit values (a,b,c) into c - -Pairs of (a,b,c) values differing in only a few bits will usually -produce values of c that look totally different. This was tested for -* pairs that differed by one bit, by two bits, in any combination - of top bits of (a,b,c), or in any combination of bottom bits of - (a,b,c). -* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed - the output delta to a Gray code (a^(a>>1)) so a string of 1's (as - is commonly produced by subtraction) look like a single 1-bit - difference. -* the base values were pseudorandom, all zero but one bit set, or - all zero plus a counter that starts at zero. - -These constants passed: - 14 11 25 16 4 14 24 - 12 14 25 16 4 14 24 -and these came close: - 4 8 15 26 3 22 24 - 10 8 15 26 3 22 24 - 11 8 15 26 3 22 24 -------------------------------------------------------------------------------- -*/ -#define final(a,b,c) \ -{ \ - c ^= b; c -= rot(b,14); \ - a ^= c; a -= rot(c,11); \ - b ^= a; b -= rot(a,25); \ - c ^= b; c -= rot(b,16); \ - a ^= c; a -= rot(c,4); \ - b ^= a; b -= rot(a,14); \ - c ^= b; c -= rot(b,24); \ -} - - - - -/* -------------------------------------------------------------------------------- -hashlittle() -- hash a variable-length key into a 32-bit value - k : the key (the unaligned variable-length array of bytes) - length : the length of the key, counting by bytes - initval : can be any 4-byte value -Returns a 32-bit value. Every bit of the key affects every bit of -the return value. Two keys differing by one or two bits will have -totally different hash values. - -The best hash table sizes are powers of 2. There is no need to do -mod a prime (mod is sooo slow!). If you need less than 32 bits, -use a bitmask. For example, if you need only 10 bits, do - h = (h & hashmask(10)); -In which case, the hash table should have hashsize(10) elements. - -If you are hashing n strings (uint8_t **)k, do it like this: - for (i=0, h=0; i 12) - { - a += k[0]; - b += k[1]; - c += k[2]; - mix(a,b,c); - length -= 12; - k += 3; - } - - /*----------------------------- handle the last (probably partial) block */ - /* - * "k[2]&0xffffff" actually reads beyond the end of the string, but - * then masks off the part it's not allowed to read. Because the - * string is aligned, the masked-off tail is in the same word as the - * rest of the string. Every machine with memory protection I've seen - * does it on word boundaries, so is OK with this. But VALGRIND will - * still catch it and complain. The masking trick does make the hash - * noticably faster for short strings (like English words). - */ -#ifndef VALGRIND - - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; - case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; - case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=k[1]&0xffffff; a+=k[0]; break; - case 6 : b+=k[1]&0xffff; a+=k[0]; break; - case 5 : b+=k[1]&0xff; a+=k[0]; break; - case 4 : a+=k[0]; break; - case 3 : a+=k[0]&0xffffff; break; - case 2 : a+=k[0]&0xffff; break; - case 1 : a+=k[0]&0xff; break; - case 0 : return c; /* zero length strings require no mixing */ - } - -#else /* make valgrind happy */ - - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[1]; a+=k[0]; break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]; break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ - case 1 : a+=k8[0]; break; - case 0 : return c; - } - -#endif /* !valgrind */ - - } else if (KS_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { - const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ - const uint8_t *k8; - - /*--------------- all but last block: aligned reads and different mixing */ - while (length > 12) - { - a += k[0] + (((uint32_t)k[1])<<16); - b += k[2] + (((uint32_t)k[3])<<16); - c += k[4] + (((uint32_t)k[5])<<16); - mix(a,b,c); - length -= 12; - k += 6; - } - - /*----------------------------- handle the last (probably partial) block */ - k8 = (const uint8_t *)k; - switch(length) - { - case 12: c+=k[4]+(((uint32_t)k[5])<<16); - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ - case 10: c+=k[4]; - b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 9 : c+=k8[8]; /* fall through */ - case 8 : b+=k[2]+(((uint32_t)k[3])<<16); - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ - case 6 : b+=k[2]; - a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 5 : b+=k8[4]; /* fall through */ - case 4 : a+=k[0]+(((uint32_t)k[1])<<16); - break; - case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ - case 2 : a+=k[0]; - break; - case 1 : a+=k8[0]; - break; - case 0 : return c; /* zero length requires no mixing */ - } - - } else { /* need to read the key one byte at a time */ - const uint8_t *k = (const uint8_t *)key; - - /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ - while (length > 12) - { - a += k[0]; - a += ((uint32_t)k[1])<<8; - a += ((uint32_t)k[2])<<16; - a += ((uint32_t)k[3])<<24; - b += k[4]; - b += ((uint32_t)k[5])<<8; - b += ((uint32_t)k[6])<<16; - b += ((uint32_t)k[7])<<24; - c += k[8]; - c += ((uint32_t)k[9])<<8; - c += ((uint32_t)k[10])<<16; - c += ((uint32_t)k[11])<<24; - mix(a,b,c); - length -= 12; - k += 12; - } - - /*-------------------------------- last block: affect all 32 bits of (c) */ - switch(length) /* all the case statements fall through */ - { - case 12: c+=((uint32_t)k[11])<<24; - case 11: c+=((uint32_t)k[10])<<16; - case 10: c+=((uint32_t)k[9])<<8; - case 9 : c+=k[8]; - case 8 : b+=((uint32_t)k[7])<<24; - case 7 : b+=((uint32_t)k[6])<<16; - case 6 : b+=((uint32_t)k[5])<<8; - case 5 : b+=k[4]; - case 4 : a+=((uint32_t)k[3])<<24; - case 3 : a+=((uint32_t)k[2])<<16; - case 2 : a+=((uint32_t)k[1])<<8; - case 1 : a+=k[0]; - break; - case 0 : return c; - } - } - - final(a,b,c); - return c; -} - - - - -#ifdef __cplusplus -} /* extern C */ -#endif - -#endif /* __KS_HASH_CWC22_H__ */ - -/* - * Copyright (c) 2002, Christopher Clark - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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. - */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_json.h b/libs/libks/src/include/ks_json.h deleted file mode 100644 index cafc9ec3dc..0000000000 --- a/libs/libks/src/include/ks_json.h +++ /dev/null @@ -1,88 +0,0 @@ -/* - Copyright (c) 2009 Dave Gamble - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*/ -#include "ks.h" -#ifndef KS_JSON__h -#define KS_JSON__h - -#ifdef __cplusplus -extern "C" -{ -#endif - -#include "ks_cJSON.h" -#include "ks_cJSON_Utils.h" - -KS_DECLARE(cJSON *) cJSON_CreateStringPrintf(const char *fmt, ...); -KS_DECLARE(const char *)cJSON_GetObjectCstr(const cJSON *object, const char *string); - -static inline cJSON *ks_json_add_child_obj(cJSON *json, const char *name, cJSON *obj) -{ - cJSON *new_json = NULL; - - ks_assert(json); - - if (obj) { - new_json = obj; - } else { - new_json = cJSON_CreateObject(); - } - - ks_assert(new_json); - - cJSON_AddItemToObject(json, name, new_json); - - return new_json; -} - -static inline cJSON *ks_json_add_child_array(cJSON *json, const char *name) -{ - cJSON *new_json = NULL; - - ks_assert(json); - - new_json = cJSON_CreateArray(); - ks_assert(new_json); - - cJSON_AddItemToObject(json, name, new_json); - - return new_json; -} - -static inline cJSON *ks_json_add_child_string(cJSON *json, const char *name, const char *val) -{ - cJSON *new_json = NULL; - - ks_assert(json); - - new_json = cJSON_CreateString(val); - ks_assert(new_json); - - cJSON_AddItemToObject(json, name, new_json); - - return new_json; -} - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/libks/src/include/ks_platform.h b/libs/libks/src/include/ks_platform.h deleted file mode 100644 index 33052e4e81..0000000000 --- a/libs/libks/src/include/ks_platform.h +++ /dev/null @@ -1,297 +0,0 @@ -/* - * Copyright (c) 2007-2015, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_PLATFORM_H_ -#define _KS_PLATFORM_H_ - -KS_BEGIN_EXTERN_C - -#if !defined(_XOPEN_SOURCE) && !defined(__FreeBSD__) && !defined(__NetBSD__) && !defined(__OpenBSD__) && !defined(__APPLE__) -#define _XOPEN_SOURCE 600 -#endif - -#if defined(__linux__) && !defined(_DEFAULT_SOURCE) -#define _DEFAULT_SOURCE 1 -#endif - -#if !defined(__WINDOWS__) && (defined(WIN32) || defined(WIN64) || defined(_MSC_VER) || defined(_WIN32)) -#define __WINDOWS__ -#ifndef _WINSOCK_DEPRECATED_NO_WARNINGS -#define _WINSOCK_DEPRECATED_NO_WARNINGS -#endif -#define _CRTDBG_MAP_ALLOC -#endif - -#ifndef _GNU_SOURCE -#define _GNU_SOURCE -#endif - -#include - -#if UINTPTR_MAX == 0xffffffffffffffff -#define KS_64BIT 1 -#endif - -#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ - __BYTE_ORDER == __LITTLE_ENDIAN) || \ - (defined(i386) || defined(__i386__) || defined(__i486__) || \ - defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) -# define KS_LITTLE_ENDIAN 1 -# define KS_BIG_ENDIAN 0 -#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ - __BYTE_ORDER == __BIG_ENDIAN) || \ - (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) -# define KS_LITTLE_ENDIAN 0 -# define KS_BIG_ENDIAN 1 -#else -# define KS_LITTLE_ENDIAN 0 -# define KS_BIG_ENDIAN 0 -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef __WINDOWS__ -#include -#include -#include -#include -#else -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#endif - -#ifdef _MSC_VER -#pragma comment(lib, "Ws2_32.lib") - -#include -/*#include -#include -#include -*/ -#ifndef open -#define open _open -#endif - -#ifndef close -#define close _close -#endif - -#ifndef read -#define read _read -#endif - -#ifndef write -#define write _write -#endif - -#ifndef __inline__ -#define __inline__ __inline -#endif - -#ifndef strdup -#define strdup _strdup -#endif - -#if (_MSC_VER >= 1400) /* VC8+ */ -#ifndef _CRT_SECURE_NO_DEPRECATE -#define _CRT_SECURE_NO_DEPRECATE -#endif -#ifndef _CRT_NONSTDC_NO_DEPRECATE -#define _CRT_NONSTDC_NO_DEPRECATE -#endif -#endif - -#ifndef strcasecmp -#define strcasecmp(s1, s2) _stricmp(s1, s2) -#endif - -#ifndef strncasecmp -#define strncasecmp(s1, s2, n) _strnicmp(s1, s2, n) -#endif - -#if (_MSC_VER < 1900) /* VC 2015 */ -#ifndef snprintf -#define snprintf _snprintf -#endif -#endif - -#ifndef S_IRUSR -#define S_IRUSR _S_IREAD -#endif - -#ifndef S_IWUSR -#define S_IWUSR _S_IWRITE -#endif - -#endif /* _MSC_VER */ - -#if (_MSC_VER >= 1400) // VC8+ -#define ks_assert(expr) assert(expr);__analysis_assume( expr ) -#endif - -#ifndef ks_assert -#define ks_assert(_x) assert(_x) -#endif - -#ifdef __WINDOWS__ - typedef SOCKET ks_socket_t; - typedef unsigned __int64 uint64_t; - typedef unsigned __int32 uint32_t; - typedef unsigned __int16 uint16_t; - typedef unsigned __int8 uint8_t; - typedef __int64 int64_t; - typedef __int32 int32_t; - typedef __int16 int16_t; - typedef __int8 int8_t; - typedef intptr_t ks_ssize_t; - typedef int ks_filehandle_t; - -#define KS_SOCK_INVALID INVALID_SOCKET -#define strerror_r(num, buf, size) strerror_s(buf, size, num) -#else -#define KS_SOCK_INVALID -1 - typedef int ks_socket_t; - typedef ssize_t ks_ssize_t; - typedef int ks_filehandle_t; -#endif - -#ifdef __WINDOWS__ -#if defined(KS_DECLARE_STATIC) -#define KS_DECLARE(type) type __stdcall -#define KS_DECLARE_NONSTD(type) type __cdecl -#define KS_DECLARE_DATA -#elif defined(KS_EXPORTS) -#define KS_DECLARE(type) __declspec(dllexport) type __stdcall -#define KS_DECLARE_NONSTD(type) __declspec(dllexport) type __cdecl -#define KS_DECLARE_DATA __declspec(dllexport) -#else -#define KS_DECLARE(type) __declspec(dllimport) type __stdcall -#define KS_DECLARE_NONSTD(type) __declspec(dllimport) type __cdecl -#define KS_DECLARE_DATA __declspec(dllimport) -#endif -#else // !WIN32 -#if (defined(__GNUC__) || defined(__SUNPRO_CC) || defined (__SUNPRO_C)) && defined(KS_API_VISIBILITY) -#define KS_DECLARE(type) __attribute__((visibility("default"))) type -#define KS_DECLARE_NONSTD(type) __attribute__((visibility("default"))) type -#define KS_DECLARE_DATA __attribute__((visibility("default"))) -#else -#define KS_DECLARE(type) type -#define KS_DECLARE_NONSTD(type) type -#define KS_DECLARE_DATA -#endif -#endif - -/* malloc or DIE macros */ -#ifdef NDEBUG -#define ks_malloc(ptr, len) (void)( (!!(ptr = malloc(len))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr ) -#define ks_zmalloc(ptr, len) (void)( (!!(ptr = calloc(1, (len)))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr) -#if (_MSC_VER >= 1500) // VC9+ -#define ks_strdup(ptr, s) (void)( (!!(ptr = _strdup(s))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr) -#else -#define ks_strdup(ptr, s) (void)( (!!(ptr = strdup(s))) || (fprintf(stderr,"ABORT! Malloc failure at: %s:%d", __FILE__, __LINE__),abort(), 0), ptr) -#endif -#else -#if (_MSC_VER >= 1500) // VC9+ -#define ks_malloc(ptr, len) (void)(assert(((ptr) = malloc((len)))),ptr);__analysis_assume( ptr ) -#define ks_zmalloc(ptr, len) (void)(assert((ptr = calloc(1, (len)))),ptr);__analysis_assume( ptr ) -#define ks_strdup(ptr, s) (void)(assert(((ptr) = _strdup(s))),ptr);__analysis_assume( ptr ) -#else -#define ks_malloc(ptr, len) (void)(assert(((ptr) = malloc((len)))),ptr) -#define ks_zmalloc(ptr, len) (void)(assert((ptr = calloc(1, (len)))),ptr) -#define ks_strdup(ptr, s) (void)(assert(((ptr) = strdup((s)))),ptr) -#endif -#endif - -#ifndef __ATTR_SAL - /* used for msvc code analysis */ - /* http://msdn2.microsoft.com/en-us/library/ms235402.aspx */ -#define _In_ -#define _In_z_ -#define _In_opt_z_ -#define _In_opt_ -#define _Printf_format_string_ -#define _Ret_opt_z_ -#define _Ret_z_ -#define _Out_opt_ -#define _Out_ -#define _Check_return_ -#define _Inout_ -#define _Inout_opt_ -#define _In_bytecount_(x) -#define _Out_opt_bytecapcount_(x) -#define _Out_bytecapcount_(x) -#define _Ret_ -#define _Post_z_ -#define _Out_cap_(x) -#define _Out_z_cap_(x) -#define _Out_ptrdiff_cap_(x) -#define _Out_opt_ptrdiff_cap_(x) -#define _Post_count_(x) -#endif - -KS_END_EXTERN_C -#endif /* defined(_KS_PLATFORM_H_) */ -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_pool.h b/libs/libks/src/include/ks_pool.h deleted file mode 100644 index 00c65ccb43..0000000000 --- a/libs/libks/src/include/ks_pool.h +++ /dev/null @@ -1,458 +0,0 @@ -/* - * Memory pool defines. - * - * Copyright 1996 by Gray Watson. - * - * This file is part of the ks_mpool package. - * - * Permission to use, copy, modify, and distribute this software for - * any purpose and without fee is hereby granted, provided that the - * above copyright notice and this permission notice appear in all - * copies, and that the name of Gray Watson not be used in advertising - * or publicity pertaining to distribution of the document or software - * without specific, written prior permission. - * - * Gray Watson makes no representations about the suitability of the - * software described herein for any purpose. It is provided "as is" - * without express or implied warranty. - * - * The author may be reached via http://256.com/gray/ - * - * $Id: ks_mpool.h,v 1.4 2006/05/31 20:26:11 gray Exp $ - */ - -#ifndef __KS_POOL_H__ -#define __KS_POOL_H__ - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -/* - * ks_pool flags to ks_pool_alloc or ks_pool_set_attr - */ - -typedef enum { - KS_POOL_FLAG_DEFAULT = 0 -} ks_pool_flag_t; - -/* - * Ks_Pool function IDs for the ks_pool_log_func callback function. - */ -#define KS_POOL_FUNC_CLOSE 1 /* ks_pool_close function called */ -#define KS_POOL_FUNC_CLEAR 2 /* ks_pool_clear function called */ -#define KS_POOL_FUNC_ALLOC 3 /* ks_pool_alloc function called */ -#define KS_POOL_FUNC_CALLOC 4 /* ks_pool_calloc function called */ -#define KS_POOL_FUNC_FREE 5 /* ks_pool_free function called */ -#define KS_POOL_FUNC_RESIZE 6 /* ks_pool_resize function called */ -#define KS_POOL_FUNC_INCREF 7 /* reference count incremented */ -#define KS_POOL_FUNC_DECREF 8 /* reference count decremented */ - - /* - ** On machines with a small stack size, you can redefine the - ** KS_PRINT_BUF_SIZE to be less than 350. But beware - for - ** smaller values some %f conversions may go into an infinite loop. - */ -#ifndef KS_PRINT_BUF_SIZE -# define KS_PRINT_BUF_SIZE 350 -#endif -#define etBUFSIZE KS_PRINT_BUF_SIZE /* Size of the output buffer */ - -/* - * void ks_pool_log_func_t - * - * DESCRIPTION: - * - * Ks_Pool transaction log function. - * - * RETURNS: - * - * None. - * - * ARGUMENT: - * - * pool -> Associated ks_pool address. - * - * func_id -> Integer function ID which identifies which ks_pool - * function is being called. - * - * byte_size -> Optionally specified byte size. - * - * ele_n -> Optionally specified element number. For ks_pool_calloc - * only. - * - * new_addr -> Optionally specified new address. For ks_pool_alloc, - * ks_pool_calloc, and ks_pool_resize only. - * - * old_addr -> Optionally specified old address. For ks_pool_resize and - * ks_pool_free only. - * - * old_byte_size -> Optionally specified old byte size. For - * ks_pool_resize only. - */ -typedef void (*ks_pool_log_func_t) (const void *pool, - const int func_id, - const ks_size_t byte_size, - const ks_size_t ele_n, const void *old_addr, const void *new_addr, const ks_size_t old_byte_size); - -/* - * ks_pool_t *ks_pool_open - * - * DESCRIPTION: - * - * Open/allocate a new memory pool. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * poolP <- pointer to new pool that will be set on success - * - */ - -KS_DECLARE(ks_status_t) ks_pool_open(ks_pool_t **poolP); - -/* - * ks_status_t ks_pool_close - * - * DESCRIPTION: - * - * Close/free a memory allocation pool previously opened with - * ks_pool_open. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * poolP <-> Pointer to pointer of our memory pool. - */ - -KS_DECLARE(ks_status_t) ks_pool_close(ks_pool_t **poolP); - -/* - * int ks_pool_clear - * - * DESCRIPTION: - * - * Wipe an opened memory pool clean so we can start again. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * pool <-> Pointer to our memory pool. - */ - -KS_DECLARE(ks_status_t) ks_pool_clear(ks_pool_t *pool); - -// @todo fill in documentation -KS_DECLARE(ks_bool_t) ks_pool_verify(void *addr); - -// @todo fill in documentation -KS_DECLARE(ks_pool_t *) ks_pool_get(void *addr); - -/* - * void *ks_pool_alloc - * - * DESCRIPTION: - * - * Allocate space for bytes inside of an already open memory pool. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * size -> Number of bytes to allocate in the pool. Must be >0. - * - */ -KS_DECLARE(void *) ks_pool_alloc(ks_pool_t *pool, const ks_size_t size); - -/* - * void *ks_pool_alloc_ex - * - * DESCRIPTION: - * - * Allocate space for bytes inside of an already open memory pool. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * size -> Number of bytes to allocate in the pool. Must be >0. - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ -KS_DECLARE(void *) ks_pool_alloc_ex(ks_pool_t *pool, const ks_size_t size, ks_status_t *error_p); - -/* - * void *ks_pool_calloc - * - * DESCRIPTION: - * - * Allocate space for elements of bytes in the memory pool and zero - * the space afterwards. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * ele_n -> Number of elements to allocate. - * - * ele_size -> Number of bytes per element being allocated. - * - */ -KS_DECLARE(void *) ks_pool_calloc(ks_pool_t *pool, const ks_size_t ele_n, const ks_size_t ele_size); - -/* - * void *ks_pool_calloc_ex - * - * DESCRIPTION: - * - * Allocate space for elements of bytes in the memory pool and zero - * the space afterwards. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * ele_n -> Number of elements to allocate. - * - * ele_size -> Number of bytes per element being allocated. - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ -KS_DECLARE(void *) ks_pool_calloc_ex(ks_pool_t *pool, const ks_size_t ele_n, const ks_size_t ele_size, ks_status_t *error_p); - -/* - * int ks_pool_free - * - * DESCRIPTION: - * - * Free an address from a memory pool. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * addr <-> Address to free. - * - */ - -KS_DECLARE(ks_status_t) ks_pool_free_ex(void **addrP); - - -/* - * void *ks_pool_ref_ex - * - * DESCRIPTION: - * - * Ref count increment an address in a memory pool. - * - * RETURNS: - * - * Success - The same pointer - * - * Failure - NULL - * - * ARGUMENTS: - * - * addr -> The addr to ref - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ - -KS_DECLARE(void *) ks_pool_ref_ex(void *addr, ks_status_t *error_p); - -#define ks_pool_ref(_x) ks_pool_ref_ex(_x, NULL) - -/* - * void *ks_pool_resize - * - * DESCRIPTION: - * - * Reallocate an address in a memory pool to a new size. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * old_addr -> Previously allocated address. - * - * new_size -> New size of the allocation. - * - */ -KS_DECLARE(void *) ks_pool_resize(void *old_addr, const ks_size_t new_size); - -/* - * void *ks_pool_resize_ex - * - * DESCRIPTION: - * - * Reallocate an address in a memory pool to a new size. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * old_addr -> Previously allocated address. - * - * new_size -> New size of the allocation. - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ -KS_DECLARE(void *) ks_pool_resize_ex(void *old_addr, const ks_size_t new_size, ks_status_t *error_p); - -/* - * int ks_pool_stats - * - * DESCRIPTION: - * - * Return stats from the memory pool. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * num_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the number of pointers currently allocated in pool. - * - * user_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the number of user bytes allocated in this pool. - * - * max_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the maximum number of user bytes that have been - * allocated in this pool. - * - * tot_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the total amount of space (including administrative - * overhead) used by the pool. - */ -KS_DECLARE(ks_status_t) ks_pool_stats(const ks_pool_t *pool, ks_size_t *num_alloced_p, ks_size_t *user_alloced_p, ks_size_t *max_alloced_p, ks_size_t *tot_alloced_p); - -/* - * int ks_pool_set_log_func - * - * DESCRIPTION: - * - * Set a logging callback function to be called whenever there was a - * memory transaction. See ks_pool_log_func_t. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * log_func -> Log function (defined in ks_pool.h) which will be called - * with each ks_pool transaction. - */ -KS_DECLARE(ks_status_t) ks_pool_set_log_func(ks_pool_t *pool, ks_pool_log_func_t log_func); - -/* - * const char *ks_pool_strerror - * - * DESCRIPTION: - * - * Return the corresponding string for the error number. - * - * RETURNS: - * - * Success - String equivalient of the error. - * - * Failure - String "invalid error code" - * - * ARGUMENTS: - * - * error -> Error number that we are converting. - */ -KS_DECLARE(const char *) ks_pool_strerror(const ks_status_t error); - -KS_DECLARE(ks_status_t) ks_pool_set_cleanup(void *ptr, void *arg, ks_pool_cleanup_callback_t callback); - -#define ks_pool_free(_x) ks_pool_free_ex((void **)_x) - -/*<<<<<<<<<< This is end of the auto-generated output from fillproto. */ - -KS_DECLARE(char *) ks_pstrdup(ks_pool_t *pool, const char *str); -KS_DECLARE(char *) ks_pstrndup(ks_pool_t *pool, const char *str, ks_size_t len); -KS_DECLARE(char *) ks_pstrmemdup(ks_pool_t *pool, const char *str, ks_size_t len); -KS_DECLARE(void *) ks_pmemdup(ks_pool_t *pool, const void *buf, ks_size_t len); -KS_DECLARE(char *) ks_pstrcat(ks_pool_t *pool, ...); -KS_DECLARE(char *) ks_psprintf(ks_pool_t *pool, const char *fmt, ...); - -KS_END_EXTERN_C - -#endif /* ! __KS_POOL_H__ */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_printf.h b/libs/libks/src/include/ks_printf.h deleted file mode 100644 index 77ce110313..0000000000 --- a/libs/libks/src/include/ks_printf.h +++ /dev/null @@ -1,82 +0,0 @@ -/* -** 2001 September 22 -** -** The author disclaims copyright to this source code. In place of -** a legal notice, here is a blessing: -** -** May you do good and not evil. -** May you find forgiveness for yourself and forgive others. -** May you share freely, never taking more than you give. -** -************************************************************************* -*/ -#ifndef KS_PRINTF_H -#define KS_PRINTF_H - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -/** - * This routine is a variant of the "sprintf()" from the - * standard C library. The resulting string is written into memory - * obtained from malloc() so that there is never a possiblity of buffer - * overflow. This routine also implement some additional formatting - * options that are useful for constructing SQL statements. - * - * The strings returned by this routine should be freed by calling - * free(). - * - * All of the usual printf formatting options apply. In addition, there - * is a "%q" option. %q works like %s in that it substitutes a null-terminated - * string from the argument list. But %q also doubles every '\'' character. - * %q is designed for use inside a string literal. By doubling each '\'' - * character it escapes that character and allows it to be inserted into - * the string. - * - * For example, so some string variable contains text as follows: - * - * char *zText = "It's a happy day!"; - * - * We can use this text in an SQL statement as follows: - * - * char *z = ks_mprintf("INSERT INTO TABLES('%q')", zText); - * ks_core_db_exec(db, z, callback1, 0, 0); - * free(z); - * - * Because the %q format string is used, the '\'' character in zText - * is escaped and the SQL generated is as follows: - * - * INSERT INTO table1 VALUES('It''s a happy day!') - * - * This is correct. Had we used %s instead of %q, the generated SQL - * would have looked like this: - * - * INSERT INTO table1 VALUES('It's a happy day!'); - * - * This second example is an SQL syntax error. As a general rule you - * should always use %q instead of %s when inserting text into a string - * literal. - */ -KS_DECLARE(char *) ks_mprintf(const char *zFormat, ...); -KS_DECLARE(char *) ks_vmprintf(const char *zFormat, va_list ap); -KS_DECLARE(char *) ks_vsnprintfv(char *zBuf, int n, const char *zFormat, va_list ap); -KS_DECLARE(char *) ks_snprintfv(char *zBuf, int n, const char *zFormat, ...); -KS_DECLARE(char *) ks_vsnprintf(char *zbuf, int n, const char *zFormat, va_list ap); -KS_DECLARE(char *) ks_vpprintf(ks_pool_t *pool, const char *zFormat, va_list ap); -KS_DECLARE(char *) ks_pprintf(ks_pool_t *pool, const char *zFormat, ...); - -KS_END_EXTERN_C - -#endif /* KS_PRINTF_H */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_q.h b/libs/libks/src/include/ks_q.h deleted file mode 100644 index bbe97f8af4..0000000000 --- a/libs/libks/src/include/ks_q.h +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Copyright (c) 2007-2015, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_Q_H_ -#define _KS_Q_H_ - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -KS_DECLARE(ks_status_t) ks_q_pop_timeout(ks_q_t *q, void **ptr, uint32_t timeout); -KS_DECLARE(ks_status_t) ks_q_wake(ks_q_t *q); -KS_DECLARE(ks_status_t) ks_q_flush(ks_q_t *q); -KS_DECLARE(ks_status_t) ks_q_set_flush_fn(ks_q_t *q, ks_flush_fn_t fn, void *flush_data); -KS_DECLARE(ks_status_t) ks_q_wait(ks_q_t *q); -KS_DECLARE(ks_size_t) ks_q_term(ks_q_t *q); -KS_DECLARE(ks_size_t) ks_q_size(ks_q_t *q); -KS_DECLARE(ks_status_t) ks_q_destroy(ks_q_t **qP); -KS_DECLARE(ks_status_t) ks_q_create(ks_q_t **qP, ks_pool_t *pool, ks_size_t maxlen); -KS_DECLARE(ks_status_t) ks_q_push(ks_q_t *q, void *ptr); -KS_DECLARE(ks_status_t) ks_q_trypush(ks_q_t *q, void *ptr); -KS_DECLARE(ks_status_t) ks_q_pop(ks_q_t *q, void **ptr); -KS_DECLARE(ks_status_t) ks_q_trypop(ks_q_t *q, void **ptr); - -KS_END_EXTERN_C - -#endif /* defined(_KS_Q_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_rng.h b/libs/libks/src/include/ks_rng.h deleted file mode 100644 index 4048995ec7..0000000000 --- a/libs/libks/src/include/ks_rng.h +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Cross Platform random/uuid abstraction - * Copyright(C) 2015 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - -#include "ks.h" - -#ifndef _KS_RNG_H -#define _KS_RNG_H - -KS_BEGIN_EXTERN_C - -#ifdef WIN32 -#include -typedef UUID uuid_t; -#else -#include -#endif - -KS_DECLARE(uuid_t *) ks_uuid(uuid_t *uuid); -KS_DECLARE(char *) ks_uuid_str(ks_pool_t *pool, uuid_t *uuid); -KS_DECLARE(ks_status_t) ks_rng_init(void); -KS_DECLARE(ks_status_t) ks_rng_shutdown(void); -KS_DECLARE(size_t) ks_rng_get_data(uint8_t* buffer, size_t length); -KS_DECLARE(size_t) ks_rng_add_entropy(const uint8_t *buffer, size_t length); -KS_DECLARE(size_t) ks_rng_seed_data(uint8_t *seed, size_t length); - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ - diff --git a/libs/libks/src/include/ks_sb.h b/libs/libks/src/include/ks_sb.h deleted file mode 100644 index e82da02ca0..0000000000 --- a/libs/libks/src/include/ks_sb.h +++ /dev/null @@ -1,66 +0,0 @@ -/* -* Copyright (c) 2017, Shane Bryldt -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of the original author; nor the names of any 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 __KS_SB_H__ -#define __KS_SB_H__ - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -typedef struct ks_sb_s ks_sb_t; - -KS_DECLARE(ks_status_t) ks_sb_create(ks_sb_t **sbP, ks_pool_t *pool, ks_size_t preallocated); -KS_DECLARE(ks_status_t) ks_sb_destroy(ks_sb_t **sbP); -KS_DECLARE(const char *) ks_sb_cstr(ks_sb_t *sb); -KS_DECLARE(ks_size_t) ks_sb_length(ks_sb_t *sb); -KS_DECLARE(ks_status_t) ks_sb_accommodate(ks_sb_t *sb, ks_size_t len); -KS_DECLARE(ks_status_t) ks_sb_append(ks_sb_t *sb, const char *str); -KS_DECLARE(ks_status_t) ks_sb_append_ex(ks_sb_t *sb, const char *str, ks_size_t len); -KS_DECLARE(ks_status_t) ks_sb_printf(ks_sb_t *sb, const char *fmt, ...); -KS_DECLARE(ks_status_t) ks_sb_json(ks_sb_t *sb, const cJSON *json); - -KS_END_EXTERN_C - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_socket.h b/libs/libks/src/include/ks_socket.h deleted file mode 100644 index b72d73d2b3..0000000000 --- a/libs/libks/src/include/ks_socket.h +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_SOCKET_H_ -#define _KS_SOCKET_H_ - -#include "ks.h" - -#ifndef WIN32 -#include -#endif - -KS_BEGIN_EXTERN_C - -#define KS_SO_NONBLOCK 2999 - -#ifdef WIN32 -#define SHUT_RDWR SD_BOTH - -static __inline int ks_errno(void) -{ - return WSAGetLastError(); -} - -static __inline int ks_errno_is_blocking(int errcode) -{ - return errcode == WSAEWOULDBLOCK || errcode == WSAEINPROGRESS || errcode == 35 || errcode == 730035; -} - -static __inline int ks_errno_is_interupt(int errcode) -{ - return 0; -} - -#else - -static inline int ks_errno(void) -{ - return errno; -} - -static inline int ks_errno_is_blocking(int errcode) -{ - return errcode == EAGAIN || errcode == EWOULDBLOCK || errcode == EINPROGRESS || errcode == EINTR || errcode == ETIMEDOUT || errcode == 35 || errcode == 730035; -} - -static inline int ks_errno_is_interupt(int errcode) -{ - return errcode == EINTR; -} - -#endif - -static __inline int ks_socket_valid(ks_socket_t s) { - return s != KS_SOCK_INVALID; -} - -#define KS_SA_INIT {AF_INET}; - -KS_DECLARE(ks_status_t) ks_socket_send(ks_socket_t sock, void *data, ks_size_t *datalen); -KS_DECLARE(ks_status_t) ks_socket_recv(ks_socket_t sock, void *data, ks_size_t *datalen); -KS_DECLARE(ks_status_t) ks_socket_sendto(ks_socket_t sock, void *data, ks_size_t *datalen, ks_sockaddr_t *addr); -KS_DECLARE(ks_status_t) ks_socket_recvfrom(ks_socket_t sock, void *data, ks_size_t *datalen, ks_sockaddr_t *addr); - -typedef struct pollfd *ks_ppollfd_t; -KS_DECLARE(int) ks_poll(ks_ppollfd_t fds, uint32_t nfds, int timeout); -KS_DECLARE(ks_status_t) ks_socket_option(ks_socket_t socket, int option_name, ks_bool_t enabled); -KS_DECLARE(ks_status_t) ks_socket_sndbuf(ks_socket_t socket, int bufsize); -KS_DECLARE(ks_status_t) ks_socket_rcvbuf(ks_socket_t socket, int bufsize); -KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags); - -KS_DECLARE(ks_socket_t) ks_socket_connect(int type, int protocol, ks_sockaddr_t *addr); -KS_DECLARE(ks_status_t) ks_addr_bind(ks_socket_t server_sock, const ks_sockaddr_t *addr); -KS_DECLARE(const char *) ks_addr_get_host(ks_sockaddr_t *addr); -KS_DECLARE(ks_port_t) ks_addr_get_port(ks_sockaddr_t *addr); -KS_DECLARE(int) ks_addr_cmp(const ks_sockaddr_t *sa1, const ks_sockaddr_t *sa2); -KS_DECLARE(ks_status_t) ks_addr_copy(ks_sockaddr_t *addr, const ks_sockaddr_t *src_addr); -KS_DECLARE(ks_status_t) ks_addr_set(ks_sockaddr_t *addr, const char *host, ks_port_t port, int family); -KS_DECLARE(ks_status_t) ks_addr_set_raw(ks_sockaddr_t *addr, const void *data, ks_port_t port, int family); -KS_DECLARE(ks_status_t) ks_addr_raw_data(const ks_sockaddr_t *addr, void **data, ks_size_t *datalen); -KS_DECLARE(ks_status_t) ks_listen(const char *host, ks_port_t port, int family, int backlog, ks_listen_callback_t callback, void *user_data); -KS_DECLARE(ks_status_t) ks_socket_shutdown(ks_socket_t sock, int how); -KS_DECLARE(ks_status_t) ks_socket_close(ks_socket_t *sock); -KS_DECLARE(ks_status_t) ks_ip_route(char *buf, int len, const char *route_ip); -KS_DECLARE(ks_status_t) ks_find_local_ip(char *buf, int len, int *mask, int family, const char *route_ip); -KS_DECLARE(ks_status_t) ks_listen_sock(ks_socket_t server_sock, ks_sockaddr_t *addr, int backlog, ks_listen_callback_t callback, void *user_data); -KS_END_EXTERN_C - -#endif /* defined(_KS_SOCKET_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_ssl.h b/libs/libks/src/include/ks_ssl.h deleted file mode 100644 index 53d758154b..0000000000 --- a/libs/libks/src/include/ks_ssl.h +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef _KS_SSL_H -#define _KS_SSL_H - -#include "ks.h" - -#include -#include -#include - -KS_BEGIN_EXTERN_C - -KS_DECLARE(void) ks_ssl_init_ssl_locks(void); -KS_DECLARE(void) ks_ssl_destroy_ssl_locks(void); -KS_DECLARE(int) ks_gen_cert(const char *dir, const char *file); - -KS_END_EXTERN_C - -#endif /* defined(_KS_SSL_H) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_thread_pool.h b/libs/libks/src/include/ks_thread_pool.h deleted file mode 100644 index 35ea8496cf..0000000000 --- a/libs/libks/src/include/ks_thread_pool.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_THREAD_POOL_H_ -#define _KS_THREAD_POOL_H_ - -KS_BEGIN_EXTERN_C -KS_DECLARE(ks_status_t) ks_thread_pool_create(ks_thread_pool_t **tp, uint32_t min, uint32_t max, size_t stack_size, - ks_thread_priority_t priority, uint32_t idle_sec); -KS_DECLARE(ks_status_t) ks_thread_pool_destroy(ks_thread_pool_t **tp); -KS_DECLARE(ks_status_t) ks_thread_pool_add_job(ks_thread_pool_t *tp, ks_thread_function_t func, void *data); -KS_DECLARE(ks_size_t) ks_thread_pool_backlog(ks_thread_pool_t *tp); - -KS_END_EXTERN_C - -#endif /* defined(_KS_THREAD_POOL_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_threadmutex.h b/libs/libks/src/include/ks_threadmutex.h deleted file mode 100644 index e5a3133554..0000000000 --- a/libs/libks/src/include/ks_threadmutex.h +++ /dev/null @@ -1,161 +0,0 @@ -/* - * Cross Platform Thread/Mutex abstraction - * Copyright(C) 2015 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - -#ifndef _KS_THREADMUTEX_H -#define _KS_THREADMUTEX_H - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -#ifdef WIN32 -#include -#define KS_THREAD_CALLING_CONVENTION __stdcall -#else -#include -#define KS_THREAD_CALLING_CONVENTION -#endif - -#define KS_THREAD_DEFAULT_STACK 240 * 1024 - - typedef struct ks_thread ks_thread_t; - typedef void *(*ks_thread_function_t) (ks_thread_t *, void *); - - typedef -#ifdef WIN32 - void * -#else - pthread_t -#endif - ks_thread_os_handle_t; - -typedef -#ifdef WIN32 - DWORD -#else - pid_t -#endif -ks_pid_t; - -typedef enum { - KS_THREAD_INIT, - KS_THREAD_RUNNING, - KS_THREAD_FAIL, - KS_THREAD_SHUTDOWN, - KS_THREAD_STOPPED -} ks_thread_state_t; - -#define KS_THREAD_IS_RUNNING(_thread) _thread->state == KS_THREAD_RUNNING - -struct ks_thread { -#ifdef WIN32 - void *handle; -#else - pthread_t handle; - pthread_attr_t attribute; -#endif - void *private_data; - ks_thread_function_t function; - size_t stack_size; - uint32_t flags; - ks_thread_state_t state; - uint8_t priority; - void *return_data; - uint8_t joined; - }; - - typedef enum { - KS_PRI_LOW = 1, - KS_PRI_NORMAL = 10, - KS_PRI_IMPORTANT = 50, - KS_PRI_REALTIME = 99, - } ks_thread_priority_t; - - typedef enum { - KS_THREAD_FLAG_DEFAULT = 0, - KS_THREAD_FLAG_DETACHED = (1 << 0) - } ks_thread_flags_t; - - KS_DECLARE(int) ks_thread_set_priority(int nice_val); - KS_DECLARE(ks_thread_os_handle_t) ks_thread_self(void); - KS_DECLARE(ks_pid_t) ks_thread_self_id(void); - KS_DECLARE(ks_thread_os_handle_t) ks_thread_os_handle(ks_thread_t *thread); - KS_DECLARE(ks_status_t) ks_thread_create_ex(ks_thread_t **thread, ks_thread_function_t func, void *data, - uint32_t flags, size_t stack_size, ks_thread_priority_t priority, ks_pool_t *pool); - KS_DECLARE(ks_status_t) ks_thread_join(ks_thread_t *thread); - KS_DECLARE(uint8_t) ks_thread_priority(ks_thread_t *thread); - -#define ks_thread_create(thread, func, data, pool) \ - ks_thread_create_ex(thread, func, data, KS_THREAD_FLAG_DEFAULT, KS_THREAD_DEFAULT_STACK, KS_PRI_NORMAL, pool) - - typedef enum { - KS_MUTEX_FLAG_DEFAULT = 0, - KS_MUTEX_FLAG_NON_RECURSIVE = (1 << 0) - } ks_mutex_flags_t; - - typedef struct ks_mutex ks_mutex_t; - - KS_DECLARE(ks_status_t) ks_mutex_create(ks_mutex_t **mutex, unsigned int flags, ks_pool_t *pool); - KS_DECLARE(ks_status_t) ks_mutex_lock(ks_mutex_t *mutex); - KS_DECLARE(ks_status_t) ks_mutex_trylock(ks_mutex_t *mutex); - KS_DECLARE(ks_status_t) ks_mutex_unlock(ks_mutex_t *mutex); - KS_DECLARE(ks_status_t) ks_mutex_destroy(ks_mutex_t **mutex); - - typedef struct ks_cond ks_cond_t; - - KS_DECLARE(ks_status_t) ks_cond_create(ks_cond_t **cond, ks_pool_t *pool); - KS_DECLARE(ks_status_t) ks_cond_create_ex(ks_cond_t **cond, ks_pool_t *pool, ks_mutex_t *mutex); - KS_DECLARE(ks_status_t) ks_cond_lock(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_trylock(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_unlock(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_signal(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_broadcast(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_try_signal(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_try_broadcast(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_wait(ks_cond_t *cond); - KS_DECLARE(ks_status_t) ks_cond_timedwait(ks_cond_t *cond, ks_time_t ms); - KS_DECLARE(ks_status_t) ks_cond_destroy(ks_cond_t **cond); - KS_DECLARE(ks_mutex_t *) ks_cond_get_mutex(ks_cond_t *cond); - - typedef struct ks_rwl ks_rwl_t; - - KS_DECLARE(ks_status_t) ks_rwl_create(ks_rwl_t **rwlock, ks_pool_t *pool); - KS_DECLARE(ks_status_t) ks_rwl_read_lock(ks_rwl_t *rwlock); - KS_DECLARE(ks_status_t) ks_rwl_write_lock(ks_rwl_t *rwlock); - KS_DECLARE(ks_status_t) ks_rwl_try_read_lock(ks_rwl_t *rwlock); - KS_DECLARE(ks_status_t) ks_rwl_try_write_lock(ks_rwl_t *rwlock); - KS_DECLARE(ks_status_t) ks_rwl_read_unlock(ks_rwl_t *rwlock); - KS_DECLARE(ks_status_t) ks_rwl_write_unlock(ks_rwl_t *rwlock); - KS_DECLARE(ks_status_t) ks_rwl_destroy(ks_rwl_t **rwlock); - - -KS_END_EXTERN_C - -#endif /* defined(_KS_THREADMUTEX_H) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_time.h b/libs/libks/src/include/ks_time.h deleted file mode 100644 index 7b13f9b31b..0000000000 --- a/libs/libks/src/include/ks_time.h +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2007-2015, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_TIME_H_ -#define _KS_TIME_H_ - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -#define KS_USEC_PER_SEC 1000000 -#define ks_time_sec(time) ((time) / KS_USEC_PER_SEC) -#define ks_time_usec(time) ((time) % KS_USEC_PER_SEC) -#define ks_time_nsec(time) (((time) % KS_USEC_PER_SEC) * 1000) -#define ks_sleep_ms(_t) ks_sleep(_t * 1000) - -KS_DECLARE(void) ks_time_init(void); -KS_DECLARE(ks_time_t) ks_time_now(void); -KS_DECLARE(ks_time_t) ks_time_now_sec(void); -KS_DECLARE(void) ks_sleep(ks_time_t microsec); - -KS_END_EXTERN_C - -#endif /* defined(_KS_TIME_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/ks_types.h b/libs/libks/src/include/ks_types.h deleted file mode 100644 index a717156bd7..0000000000 --- a/libs/libks/src/include/ks_types.h +++ /dev/null @@ -1,252 +0,0 @@ -/* - * Copyright (c) 2007-2015, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KS_TYPES_H_ -#define _KS_TYPES_H_ - -#include "ks.h" - -KS_BEGIN_EXTERN_C - -#define KS_STR2ENUM_P(_FUNC1, _FUNC2, _TYPE) KS_DECLARE(_TYPE) _FUNC1 (const char *name); KS_DECLARE(const char *) _FUNC2 (_TYPE type); - -#define KS_STR2ENUM(_FUNC1, _FUNC2, _TYPE, _STRINGS, _MAX) \ - KS_DECLARE(_TYPE) _FUNC1 (const char *name) \ - { \ - int i; \ - _TYPE t = _MAX ; \ - \ - for (i = 0; i < _MAX ; i++) { \ - if (!strcasecmp(name, _STRINGS[i])) { \ - t = (_TYPE) i; \ - break; \ - } \ - } \ - \ - return t; \ - } \ - KS_DECLARE(const char *) _FUNC2 (_TYPE type) \ - { \ - if (type > _MAX) { \ - type = _MAX; \ - } \ - return _STRINGS[(int)type]; \ - } \ - -#define KS_ENUM_NAMES(_NAME, _STRINGS) static const char * _NAME [] = { _STRINGS , NULL }; - -#define KS_VA_NONE "%s", "" - - typedef enum { - KS_POLL_READ = (1 << 0), - KS_POLL_WRITE = (1 << 1), - KS_POLL_ERROR = (1 << 2) - } ks_poll_t; - -#if defined(_MSC_VER) -#include - typedef SSIZE_T ssize_t; -#endif - - typedef uint16_t ks_port_t; - typedef size_t ks_size_t; - typedef unsigned char ks_byte_t; - typedef enum { - KS_STATUS_SUCCESS, - KS_STATUS_FAIL, - KS_STATUS_BREAK, - KS_STATUS_DISCONNECTED, - KS_STATUS_GENERR, - KS_STATUS_INACTIVE, - KS_STATUS_TIMEOUT, - KS_STATUS_DUPLICATE_OPERATION, - /* Memory pool errors */ - KS_STATUS_REFS_EXIST, /* references exist */ - KS_STATUS_ARG_NULL, /* function argument is null */ - KS_STATUS_ARG_INVALID, /* function argument is invalid */ - KS_STATUS_PNT, /* invalid ks_pool pointer */ - KS_STATUS_POOL_OVER, /* ks_pool structure was overwritten */ - KS_STATUS_PAGE_SIZE, /* could not get system page-size */ - KS_STATUS_OPEN_ZERO, /* could not open /dev/zero */ - KS_STATUS_NO_MEM, /* no memory available */ - KS_STATUS_SIZE, /* error processing requested size */ - KS_STATUS_TOO_BIG, /* allocation exceeded max size */ - KS_STATUS_MEM, /* invalid memory address */ - KS_STATUS_MEM_OVER, /* memory lower bounds overwritten */ - KS_STATUS_NOT_FOUND, /* memory block not found in pool */ - KS_STATUS_IS_FREE, /* memory block already free */ - KS_STATUS_BLOCK_STAT, /* invalid internal block status */ - KS_STATUS_FREE_ADDR, /* invalid internal free address */ - KS_STATUS_NO_PAGES, /* ran out of pages in pool */ - KS_STATUS_ALLOC, /* calloc,malloc,free,realloc failed */ - KS_STATUS_PNT_OVER, /* pointer structure was overwritten */ - KS_STATUS_INVALID_POINTER, /* address is not valid */ - KS_STATUS_NOT_ALLOWED, /* operation is not allowed */ - /* Always insert new entries above this line*/ - KS_STATUS_COUNT - } ks_status_t; - -#define STATUS_STRINGS\ - "SUCCESS",\ - "FAIL",\ - "BREAK",\ - "DISCONNECTED",\ - "GENERR",\ - "INACTIVE",\ - "TIMEOUT",\ - "DUPLICATE_OPERATION",\ - "ARG_NULL",\ - "ARG_INVALID",\ - "PNT",\ - "POOL_OVER",\ - "PAGE_SIZE",\ - "OPEN_ZERO",\ - "NO_MEM",\ - "SIZE",\ - "TOO_BIG",\ - "MEM",\ - "MEM_OVER",\ - "NOT_FOUN",\ - "IS_FREE",\ - "BLOCK_STAT",\ - "FREE_ADDR",\ - "NO_PAGES",\ - "ALLOC",\ - "PNT_OVER",\ - "INVALID_POINTER",\ - /* insert new entries before this */\ - "COUNT" - - KS_STR2ENUM_P(ks_str2ks_status, ks_status2str, ks_status_t) - -/*! \brief Used internally for truth test */ - typedef enum { - KS_TRUE = 1, - KS_FALSE = 0 - } ks_bool_t; - -#ifndef __FUNCTION__ -#define __FUNCTION__ (const char *)__func__ -#endif - -#define KS_PRE __FILE__, __FUNCTION__, __LINE__ -#define KS_LOG_LEVEL_DEBUG 7 -#define KS_LOG_LEVEL_INFO 6 -#define KS_LOG_LEVEL_NOTICE 5 -#define KS_LOG_LEVEL_WARNING 4 -#define KS_LOG_LEVEL_ERROR 3 -#define KS_LOG_LEVEL_CRIT 2 -#define KS_LOG_LEVEL_ALERT 1 -#define KS_LOG_LEVEL_EMERG 0 - -#define KS_LOG_DEBUG KS_PRE, KS_LOG_LEVEL_DEBUG -#define KS_LOG_INFO KS_PRE, KS_LOG_LEVEL_INFO -#define KS_LOG_NOTICE KS_PRE, KS_LOG_LEVEL_NOTICE -#define KS_LOG_WARNING KS_PRE, KS_LOG_LEVEL_WARNING -#define KS_LOG_ERROR KS_PRE, KS_LOG_LEVEL_ERROR -#define KS_LOG_CRIT KS_PRE, KS_LOG_LEVEL_CRIT -#define KS_LOG_ALERT KS_PRE, KS_LOG_LEVEL_ALERT -#define KS_LOG_EMERG KS_PRE, KS_LOG_LEVEL_EMERG - -typedef enum { - KS_LOG_PREFIX_NONE = 0, - - KS_LOG_PREFIX_LEVEL = 1 << 0, - KS_LOG_PREFIX_FILE = 1 << 1, - KS_LOG_PREFIX_LINE = 1 << 2, - KS_LOG_PREFIX_FUNC = 1 << 3, - KS_LOG_PREFIX_THREAD = 1 << 4, - KS_LOG_PREFIX_TIME = 1 << 5, - - KS_LOG_PREFIX_ALL = KS_LOG_PREFIX_LEVEL | KS_LOG_PREFIX_FILE | KS_LOG_PREFIX_LINE | KS_LOG_PREFIX_FUNC | KS_LOG_PREFIX_THREAD | KS_LOG_PREFIX_TIME, -} ks_log_prefix_t; - -struct ks_pool_s; - -typedef struct ks_pool_s ks_pool_t; -typedef void (*ks_hash_destructor_t)(void *ptr); - -typedef enum { - KS_MPCL_ANNOUNCE, - KS_MPCL_TEARDOWN, - KS_MPCL_DESTROY -} ks_pool_cleanup_action_t; - -typedef enum { - KS_MPCL_FREE, - KS_MPCL_GLOBAL_FREE, -} ks_pool_cleanup_type_t; - -typedef union { - struct sockaddr_in v4; - struct sockaddr_in6 v6; -} ks_sockaddr_in_t; - -typedef struct { - int family; - ks_sockaddr_in_t v; - ks_port_t port; - char host[48]; -} ks_sockaddr_t; - -typedef void (*ks_pool_cleanup_callback_t)(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type); - -typedef void (*ks_logger_t) (const char *file, const char *func, int line, int level, const char *fmt, ...); -typedef void (*ks_listen_callback_t) (ks_socket_t server_sock, ks_socket_t client_sock, ks_sockaddr_t *addr, void *user_data); - -typedef int64_t ks_time_t; - -struct ks_q_s; -typedef struct ks_q_s ks_q_t; -typedef void (*ks_flush_fn_t)(ks_q_t *q, void *ptr, void *flush_data); - -typedef struct ks_thread_pool_s ks_thread_pool_t; - -struct ks_network_list; -typedef struct ks_network_list ks_network_list_t; - - -KS_END_EXTERN_C - -#endif /* defined(_KS_TYPES_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/kws.h b/libs/libks/src/include/kws.h deleted file mode 100644 index 734591ab59..0000000000 --- a/libs/libks/src/include/kws.h +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 _KWS_H -#define _KWS_H - -#define WEBSOCKET_GUID "258EAFA5-E914-47DA-95CA-C5AB0DC85B11" -#define B64BUFFLEN 1024 -#include "ks.h" - -KS_BEGIN_EXTERN_C - -typedef enum { - WS_NONE = 0, - WS_NORMAL = 1000, - WS_PROTO_ERR = 1002, - WS_DATA_TOO_BIG = 1009 -} kws_cause_t; - -typedef enum { - WSOC_CONTINUATION = 0x0, - WSOC_TEXT = 0x1, - WSOC_BINARY = 0x2, - WSOC_CLOSE = 0x8, - WSOC_PING = 0x9, - WSOC_PONG = 0xA -} kws_opcode_t; - -typedef enum { - KWS_CLIENT, - KWS_SERVER -} kws_type_t; - -typedef enum { - KWS_CLOSE_SOCK, - KWS_BLOCK, - KWS_STAY_OPEN -} kws_flag_t; - -struct kws_s; -typedef struct kws_s kws_t; - - -KS_DECLARE(ks_ssize_t) kws_read_frame(kws_t *kws, kws_opcode_t *oc, uint8_t **data); -KS_DECLARE(ks_ssize_t) kws_write_frame(kws_t *kws, kws_opcode_t oc, void *data, ks_size_t bytes); -KS_DECLARE(ks_ssize_t) kws_raw_read(kws_t *kws, void *data, ks_size_t bytes, int block); -KS_DECLARE(ks_ssize_t) kws_raw_write(kws_t *kws, void *data, ks_size_t bytes); -KS_DECLARE(ks_status_t) kws_init(kws_t **kwsP, ks_socket_t sock, SSL_CTX *ssl_ctx, const char *client_data, kws_flag_t flags, ks_pool_t *pool); -KS_DECLARE(ks_ssize_t) kws_close(kws_t *kws, int16_t reason); -KS_DECLARE(void) kws_destroy(kws_t **kwsP); -KS_DECLARE(ks_status_t) kws_get_buffer(kws_t *kws, char **bufP, ks_size_t *buflen); -KS_DECLARE(ks_size_t) kws_sans_count(kws_t *kws); -KS_DECLARE(const char *) kws_sans_get(kws_t *kws, ks_size_t index); - - - - -#if 0 -static inline uint64_t get_unaligned_uint64(const void *p) -{ - const struct { uint64_t d; } __attribute__((packed)) *pp = p; - return pp->d; -} -#endif - -KS_END_EXTERN_C - -#endif /* defined(_KWS_H_) */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/include/simclist.h b/libs/libks/src/include/simclist.h deleted file mode 100755 index 9af68e37a5..0000000000 --- a/libs/libks/src/include/simclist.h +++ /dev/null @@ -1,1007 +0,0 @@ -/* -* Copyright (c) 2007,2008 Mij -* -* 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. -*/ - - -/* -* Original SimCList library. See http://mij.oltrelinux.com/devel/simclist -*/ - - -#ifndef SIMCLIST_H -#define SIMCLIST_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include -#include -#include -#include - -#ifndef SIMCLIST_NO_DUMPRESTORE -# ifndef _WIN32 -# include /* list_dump_info_t's struct timeval */ -# else -# include -# endif -#endif - - - /* Be friend of both C90 and C99 compilers */ -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L - /* "inline" and "restrict" are keywords */ -#else -#ifndef inline -# define inline /* inline */ -#endif -#ifndef restrict -# define restrict /* restrict */ -#endif -#endif - - - /** - * Type representing list hashes. - * - * This is a signed integer value. - */ - typedef int32_t ks_list_hash_t; - -#ifndef SIMCLIST_NO_DUMPRESTORE - typedef struct { - uint16_t version; /* dump version */ - struct timeval timestamp; /* when the list has been dumped, seconds since UNIX epoch */ - uint32_t list_size; - uint32_t list_numels; - ks_list_hash_t list_hash; /* hash of the list when dumped, or 0 if invalid */ - uint32_t dumpsize; - int consistent; /* 1 if the dump is verified complete/consistent; 0 otherwise */ - } ks_list_dump_info_t; -#endif - - /** - * a comparator of elements. - * - * A comparator of elements is a function that: - * -# receives two references to elements a and b - * -# returns {<0, 0, >0} if (a > b), (a == b), (a < b) respectively - * - * It is responsability of the function to handle possible NULL values. - */ - typedef int(*element_comparator)(const void *a, const void *b); - - /** - * a seeker of elements. - * - * An element seeker is a function that: - * -# receives a reference to an element el - * -# receives a reference to some indicator data - * -# returns non-0 if the element matches the indicator, 0 otherwise - * - * It is responsability of the function to handle possible NULL values in any - * argument. - */ - typedef int(*element_seeker)(const void *el, const void *indicator); - - /** - * an element lenght meter. - * - * An element meter is a function that: - * -# receives the reference to an element el - * -# returns its size in bytes - * - * It is responsability of the function to handle possible NULL values. - */ - typedef ks_size_t(*element_meter)(const void *el); - - /** - * a function computing the hash of elements. - * - * An hash computing function is a function that: - * -# receives the reference to an element el - * -# returns a hash value for el - * - * It is responsability of the function to handle possible NULL values. - */ - typedef ks_list_hash_t(*element_hash_computer)(const void *el); - - /** - * a function for serializing an element. - * - * A serializer function is one that gets a reference to an element, - * and returns a reference to a buffer that contains its serialization - * along with the length of this buffer. - * It is responsability of the function to handle possible NULL values, - * returning a NULL buffer and a 0 buffer length. - * - * These functions have 3 goals: - * -# "freeze" and "flatten" the memory representation of the element - * -# provide a portable (wrt byte order, or type size) representation of the element, if the dump can be used on different sw/hw combinations - * -# possibly extract a compressed representation of the element - * - * @param el reference to the element data - * @param serialize_buffer reference to fill with the length of the buffer - * @return reference to the buffer with the serialized data - */ - typedef void *(*element_serializer)(const void *restrict el, uint32_t *restrict serializ_len); - - /** - * a function for un-serializing an element. - * - * An unserializer function accomplishes the inverse operation of the - * serializer function. An unserializer function is one that gets a - * serialized representation of an element and turns it backe to the original - * element. The serialized representation is passed as a reference to a buffer - * with its data, and the function allocates and returns the buffer containing - * the original element, and it sets the length of this buffer into the - * integer passed by reference. - * - * @param data reference to the buffer with the serialized representation of the element - * @param data_len reference to the location where to store the length of the data in the buffer returned - * @return reference to a buffer with the original, unserialized representation of the element - */ - typedef void *(*element_unserializer)(const void *restrict data, uint32_t *restrict data_len); - - /* [private-use] list entry -- olds actual user datum */ - struct ks_list_entry_s { - void *data; - - /* doubly-linked list service references */ - struct ks_list_entry_s *next; - struct ks_list_entry_s *prev; - }; - - /* [private-use] list attributes */ - struct ks_list_attributes_s { - /* user-set routine for comparing list elements */ - element_comparator comparator; - /* user-set routing for seeking elements */ - element_seeker seeker; - /* user-set routine for determining the length of an element */ - element_meter meter; - int copy_data; - /* user-set routine for computing the hash of an element */ - element_hash_computer hasher; - /* user-set routine for serializing an element */ - element_serializer serializer; - /* user-set routine for unserializing an element */ - element_unserializer unserializer; - }; - - /** list object */ - typedef struct { - ks_rwl_t *lock; - - struct ks_list_entry_s *head_sentinel; - struct ks_list_entry_s *tail_sentinel; - struct ks_list_entry_s *mid; - - unsigned int numels; - - /* array of spare elements */ - struct ks_list_entry_s **spareels; - unsigned int spareelsnum; - -#ifdef SIMCLIST_WITH_THREADS - /* how many threads are currently running */ - unsigned int threadcount; -#endif - - /* service variables for list iteration */ - int iter_active; - unsigned int iter_pos; - struct ks_list_entry_s *iter_curentry; - - /* list attributes */ - struct ks_list_attributes_s attrs; - } ks_list_t; - - /** - * initialize a list object for use. - * - * @param list must point to a user-provided memory location for a pointer to allocate - * @param pool pool for lifecycle and auto cleanup - * @return KS_STATUS_SUCCESS for success. - */ - KS_DECLARE(ks_status_t) ks_list_create(ks_list_t **list, ks_pool_t *pool); - - /** - * completely remove the list from memory. - * - * This function is the inverse of ks_list_create(). It is meant to be called when - * the list is no longer going to be used. Elements and possible memory taken - * for internal use are freed. - * - * @param list pointer to pointer of list to destroy - * @return KS_STATUS_SUCCESS for success. - */ - KS_DECLARE(ks_status_t) ks_list_destroy(ks_list_t **list); - - /** - * set the comparator function for list elements. - * - * Comparator functions are used for searching and sorting. If NULL is passed - * as reference to the function, the comparator is disabled. - * - * @param l list to operate - * @param comparator_fun pointer to the actual comparator function - * @return 0 if the attribute was successfully set; -1 otherwise - * - * @see element_comparator() - */ - int ks_list_attributes_comparator(ks_list_t *restrict l, element_comparator comparator_fun); - - /** - * set a seeker function for list elements. - * - * Seeker functions are used for finding elements. If NULL is passed as reference - * to the function, the seeker is disabled. - * - * @param l list to operate - * @param seeker_fun pointer to the actual seeker function - * @return 0 if the attribute was successfully set; -1 otherwise - * - * @see element_seeker() - */ - int ks_list_attributes_seeker(ks_list_t *restrict l, element_seeker seeker_fun); - - /** - * require to free element data when list entry is removed (default: don't free). - * - * [ advanced preference ] - * - * By default, when an element is removed from the list, it disappears from - * the list by its actual data is not free()d. With this option, every - * deletion causes element data to be freed. - * - * It is responsability of this function to correctly handle NULL values, if - * NULL elements are inserted into the list. - * - * @param l list to operate - * @param metric_fun pointer to the actual metric function - * @param copy_data 0: do not free element data (default); non-0: do free - * @return 0 if the attribute was successfully set; -1 otherwise - * - * @see element_meter() - * @see ks_list_meter_int8_t() - * @see ks_list_meter_int16_t() - * @see ks_list_meter_int32_t() - * @see ks_list_meter_int64_t() - * @see ks_list_meter_uint8_t() - * @see ks_list_meter_uint16_t() - * @see ks_list_meter_uint32_t() - * @see ks_list_meter_uint64_t() - * @see ks_list_meter_float() - * @see ks_list_meter_double() - * @see ks_list_meter_string() - */ - int ks_list_attributes_copy(ks_list_t *restrict l, element_meter metric_fun, int copy_data); - - /** - * set the element hash computing function for the list elements. - * - * [ advanced preference ] - * - * An hash can be requested depicting the list status at a given time. An hash - * only depends on the elements and their order. By default, the hash of an - * element is only computed on its reference. With this function, the user can - * set a custom function computing the hash of an element. If such function is - * provided, the list_hash() function automatically computes the list hash using - * the custom function instead of simply referring to element references. - * - * @param l list to operate - * @param hash_computer_fun pointer to the actual hash computing function - * @return 0 if the attribute was successfully set; -1 otherwise - * - * @see element_hash_computer() - */ - int ks_list_attributes_hash_computer(ks_list_t *restrict l, element_hash_computer hash_computer_fun); - - /** - * set the element serializer function for the list elements. - * - * [ advanced preference ] - * - * Serialize functions are used for dumping the list to some persistent - * storage. The serializer function is called for each element; it is passed - * a reference to the element and a reference to a ks_size_t object. It will - * provide (and return) the buffer with the serialization of the element and - * fill the ks_size_t object with the length of this serialization data. - * - * @param l list to operate - * @param serializer_fun pointer to the actual serializer function - * @return 0 if the attribute was successfully set; -1 otherwise - * - * @see element_serializer() - * @see ks_list_dump_filedescriptor() - * @see ks_list_restore_filedescriptor() - */ - int ks_list_attributes_serializer(ks_list_t *restrict l, element_serializer serializer_fun); - - /** - * set the element unserializer function for the list elements. - * - * [ advanced preference ] - * - * Unserialize functions are used for restoring the list from some persistent - * storage. The unserializer function is called for each element segment read - * from the storage; it is passed the segment and a reference to an integer. - * It shall allocate and return a buffer compiled with the resumed memory - * representation of the element, and set the integer value to the length of - * this buffer. - * - * @param l list to operate - * @param unserializer_fun pointer to the actual unserializer function - * @return 0 if the attribute was successfully set; -1 otherwise - * - * @see element_unserializer() - * @see ks_list_dump_filedescriptor() - * @see ks_list_restore_filedescriptor() - */ - int ks_list_attributes_unserializer(ks_list_t *restrict l, element_unserializer unserializer_fun); - - /** - * append data at the end of the list. - * - * This function is useful for adding elements with a FIFO/queue policy. - * - * @param l list to operate - * @param data pointer to user data to append - * - * @return 1 for success. < 0 for failure - */ - KS_DECLARE(int) ks_list_append(ks_list_t *restrict l, const void *data); - - /** - * insert data in the head of the list. - * - * This function is useful for adding elements with a LIFO/Stack policy. - * - * @param l list to operate - * @param data pointer to user data to append - * - * @return 1 for success. < 0 for failure - */ - KS_DECLARE(int) ks_list_prepend(ks_list_t *restrict l, const void * data); - - /** - * extract the element in the top of the list. - * - * This function is for using a list with a FIFO/queue policy. - * - * @param l list to operate - * @return reference to user datum, or NULL on errors - */ - KS_DECLARE(void *) ks_list_fetch(ks_list_t *restrict l); - - /** - * retrieve an element at a given position. - * - * @param l list to operate - * @param pos [0,size-1] position index of the element wanted - * @return reference to user datum, or NULL on errors - */ - KS_DECLARE(void *) ks_list_get_at(const ks_list_t *restrict l, unsigned int pos); - - /** - * return the maximum element of the list. - * - * @warning Requires a comparator function to be set for the list. - * - * Returns the maximum element with respect to the comparator function output. - * - * @see ks_list_attributes_comparator() - * - * @param l list to operate - * @return the reference to the element, or NULL - */ - KS_DECLARE(void *) ks_list_get_max(const ks_list_t *restrict l); - - /** - * return the minimum element of the list. - * - * @warning Requires a comparator function to be set for the list. - * - * Returns the minimum element with respect to the comparator function output. - * - * @see ks_list_attributes_comparator() - * - * @param l list to operate - * @return the reference to the element, or NULL - */ - KS_DECLARE(void *) ks_list_get_min(const ks_list_t *restrict l); - - /** - * retrieve and remove from list an element at a given position. - * - * @param l list to operate - * @param pos [0,size-1] position index of the element wanted - * @return reference to user datum, or NULL on errors - */ - KS_DECLARE(void *) ks_list_extract_at(ks_list_t *restrict l, unsigned int pos); - - /** - * insert an element at a given position. - * - * @param l list to operate - * @param data reference to data to be inserted - * @param pos [0,size-1] position index to insert the element at - * @return positive value on success. Negative on failure - */ - KS_DECLARE(int) ks_list_insert_at(ks_list_t *restrict l, const void *data, unsigned int pos); - - /** - * expunge the first found given element from the list. - * - * Inspects the given list looking for the given element; if the element - * is found, it is removed. Only the first occurence is removed. - * If a comparator function was not set, elements are compared by reference. - * Otherwise, the comparator is used to match the element. - * - * @param l list to operate - * @param data reference of the element to search for - * @return 0 on success. Negative value on failure - * - * @see ks_list_attributes_comparator() - * @see ks_list_delete_at() - */ - KS_DECLARE(int) ks_list_delete(ks_list_t *restrict l, const void *data); - - /** - * expunge an element at a given position from the list. - * - * @param l list to operate - * @param pos [0,size-1] position index of the element to be deleted - * @return 0 on success. Negative value on failure - */ - KS_DECLARE(int) ks_list_delete_at(ks_list_t *restrict l, unsigned int pos); - - /** - * expunge an element at the current iterator position from the list. - * - * @param l list to operate - * @return 0 on success. Negative value on failure - */ - KS_DECLARE(int) ks_list_delete_iterator(ks_list_t *restrict l); - - /** - * expunge an array of elements from the list, given their position range. - * - * @param l list to operate - * @param posstart [0,size-1] position index of the first element to be deleted - * @param posend [posstart,size-1] position of the last element to be deleted - * @return the number of elements successfully removed on success, <0 on error - */ - KS_DECLARE(int) ks_list_delete_range(ks_list_t *restrict l, unsigned int posstart, unsigned int posend); - - /** - * clear all the elements off of the list. - * - * The element datums will not be freed. - * - * @see ks_list_delete_range() - * @see ks_list_size() - * - * @param l list to operate - * @return the number of elements removed on success, <0 on error - */ - KS_DECLARE(int) ks_list_clear(ks_list_t *restrict l); - - /** - * inspect the number of elements in the list. - * - * @param l list to operate - * @return number of elements currently held by the list - */ - KS_DECLARE(unsigned int) ks_list_size(const ks_list_t *restrict l); - - /** - * inspect whether the list is empty. - * - * @param l list to operate - * @return 0 iff the list is not empty - * - * @see ks_list_size() - */ - KS_DECLARE(int) ks_list_empty(const ks_list_t *restrict l); - - /** - * find the position of an element in a list. - * - * @warning Requires a comparator function to be set for the list. - * - * Inspects the given list looking for the given element; if the element - * is found, its position into the list is returned. - * Elements are inspected comparing references if a comparator has not been - * set. Otherwise, the comparator is used to find the element. - * - * @param l list to operate - * @param data reference of the element to search for - * @return position of element in the list, or <0 if not found - * - * @see ks_list_attributes_comparator() - * @see ks_list_get_at() - */ - KS_DECLARE(int) ks_list_locate(const ks_list_t *restrict l, const void *data, ks_bool_t prelocked); - - /** - * returns an element given an indicator. - * - * @warning Requires a seeker function to be set for the list. - * - * Inspect the given list looking with the seeker if an element matches - * an indicator. If such element is found, the reference to the element - * is returned. - * - * @param l list to operate - * @param indicator indicator data to pass to the seeker along with elements - * @return reference to the element accepted by the seeker, or NULL if none found - */ - KS_DECLARE(void *) ks_list_seek(ks_list_t *restrict l, const void *indicator); - - /** - * inspect whether some data is member of the list. - * - * @warning Requires a comparator function to be set for the list. - * - * By default, a per-reference comparison is accomplished. That is, - * the data is in list if any element of the list points to the same - * location of data. - * A "semantic" comparison is accomplished, otherwise, if a comparator - * function has been set previously, with ks_list_attributes_comparator(); - * in which case, the given data reference is believed to be in list iff - * comparator_fun(elementdata, userdata) == 0 for any element in the list. - * - * @param l list to operate - * @param data reference to the data to search - * @return 0 iff the list does not contain data as an element - * - * @see ks_list_attributes_comparator() - */ - KS_DECLARE(int) ks_list_contains(const ks_list_t *restrict l, const void *data); - - /** - * concatenate two lists - * - * Concatenates one list with another, and stores the result into a - * user-provided list object, which must be different from both the - * lists to concatenate. Attributes from the original lists are not - * cloned. - * The destination list referred is threated as virgin room: if it - * is an existing list containing elements, memory leaks will happen. - * It is OK to specify the same list twice as source, for "doubling" - * it in the destination. - * - * @param l1 base list - * @param l2 list to append to the base - * @param dest reference to the destination list - * @return 0 for success, -1 for errors - */ - KS_DECLARE(int) ks_list_concat(const ks_list_t *l1, const ks_list_t *l2, ks_list_t *restrict dest); - - /** - * sort list elements. - * - * @warning Requires a comparator function to be set for the list. - * - * Sorts the list in ascending or descending order as specified by the versus - * flag. The algorithm chooses autonomously what algorithm is best suited for - * sorting the list wrt its current status. - * - * @param l list to operate - * @param versus positive: order small to big; negative: order big to small - * @return 0 iff sorting was successful - * - * @see ks_list_attributes_comparator() - */ - KS_DECLARE(int) ks_list_sort(ks_list_t *restrict l, int versus); - - /** - * start an iteration session. - * - * This function prepares the list to be iterated. - * - * @param l list to operate - * @return 0 if the list cannot be currently iterated. >0 otherwise - * - * @see ks_list_iterator_stop() - */ - KS_DECLARE(int) ks_list_iterator_start(ks_list_t *restrict l); - - /** - * return the next element in the iteration session. - * - * @param l list to operate - * @return element datum, or NULL on errors - */ - KS_DECLARE(void *) ks_list_iterator_next(ks_list_t *restrict l); - - /** - * inspect whether more elements are available in the iteration session. - * - * @param l list to operate - * @return 0 iff no more elements are available. - */ - KS_DECLARE(int) ks_list_iterator_hasnext(const ks_list_t *restrict l); - - /** - * end an iteration session. - * - * @param l list to operate - * @return 0 iff the iteration session cannot be stopped - */ - KS_DECLARE(int) ks_list_iterator_stop(ks_list_t *restrict l); - - /** - * return the hash of the current status of the list. - * - * @param l list to operate - * @param hash where the resulting hash is put - * - * @return 0 for success; <0 for failure - */ - KS_DECLARE(int) ks_list_hash(const ks_list_t *restrict l, ks_list_hash_t *restrict hash); - -#ifndef SIMCLIST_NO_DUMPRESTORE - /** - * get meta informations on a list dump on filedescriptor. - * - * [ advanced function ] - * - * Extracts the meta information from a SimCList dump located in a file - * descriptor. The file descriptor must be open and positioned at the - * beginning of the SimCList dump block. - * - * @param fd file descriptor to get metadata from - * @param info reference to a dump metainformation structure to fill - * @return 0 for success; <0 for failure - * - * @see ks_list_dump_filedescriptor() - */ - int ks_list_dump_getinfo_filedescriptor(int fd, ks_list_dump_info_t *restrict info); - - /** - * get meta informations on a list dump on file. - * - * [ advanced function ] - * - * Extracts the meta information from a SimCList dump located in a file. - * - * @param filename filename of the file to fetch from - * @param info reference to a dump metainformation structure to fill - * @return 0 for success; <0 for failure - * - * @see ks_list_dump_filedescriptor() - */ - int ks_list_dump_getinfo_file(const char *restrict filename, ks_list_dump_info_t *restrict info); - - /** - * dump the list into an open, writable file descriptor. - * - * This function "dumps" the list to a persistent storage so it can be - * preserved across process terminations. - * When called, the file descriptor must be open for writing and positioned - * where the serialized data must begin. It writes its serialization of the - * list in a form which is portable across different architectures. Dump can - * be safely performed on stream-only (non seekable) descriptors. The file - * descriptor is not closed at the end of the operations. - * - * To use dump functions, either of these conditions must be satisfied: - * -# a metric function has been specified with ks_list_attributes_copy() - * -# a serializer function has been specified with ks_list_attributes_serializer() - * - * If a metric function has been specified, each element of the list is dumped - * as-is from memory, copying it from its pointer for its length down to the - * file descriptor. This might have impacts on portability of the dump to - * different architectures. - * - * If a serializer function has been specified, its result for each element is - * dumped to the file descriptor. - * - * - * @param l list to operate - * @param fd file descriptor to write to - * @param len location to store the resulting length of the dump (bytes), or NULL - * - * @return 0 if successful; -1 otherwise - * - * @see element_serializer() - * @see ks_list_attributes_copy() - * @see ks_list_attributes_serializer() - */ - int ks_list_dump_filedescriptor(const ks_list_t *restrict l, int fd, ks_size_t *restrict len); - - /** - * dump the list to a file name. - * - * This function creates a filename and dumps the current content of the list - * to it. If the file exists it is overwritten. The number of bytes written to - * the file can be returned in a specified argument. - * - * @param l list to operate - * @param filename filename to write to - * @param len location to store the resulting length of the dump (bytes), or NULL - * - * @return 0 if successful; -1 otherwise - * - * @see ks_list_attributes_copy() - * @see element_serializer() - * @see ks_list_attributes_serializer() - * @see ks_list_dump_filedescriptor() - * @see ks_list_restore_file() - * - * This function stores a representation of the list - */ - int ks_list_dump_file(const ks_list_t *restrict l, const char *restrict filename, ks_size_t *restrict len); - - /** - * restore the list from an open, readable file descriptor to memory. - * - * This function is the "inverse" of ks_list_dump_filedescriptor(). It restores - * the list content from a (open, read-ready) file descriptor to memory. An - * unserializer might be needed to restore elements from the persistent - * representation back into memory-consistent format. List attributes can not - * be restored and must be set manually. - * - * @see ks_list_dump_filedescriptor() - * @see ks_list_attributes_serializer() - * @see ks_list_attributes_unserializer() - * - * @param l list to restore to - * @param fd file descriptor to read from. - * @param len location to store the length of the dump read (bytes), or NULL - * @return 0 if successful; -1 otherwise - */ - int ks_list_restore_filedescriptor(ks_list_t *restrict l, int fd, ks_size_t *restrict len); - - /** - * restore the list from a file name. - * - * This function restores the content of a list from a file into memory. It is - * the inverse of ks_list_dump_file(). - * - * @see element_unserializer() - * @see ks_list_attributes_unserializer() - * @see ks_list_dump_file() - * @see ks_list_restore_filedescriptor() - * - * @param l list to restore to - * @param filename filename to read data from - * @param len location to store the length of the dump read (bytes), or NULL - * @return 0 if successful; -1 otherwise - */ - int ks_list_restore_file(ks_list_t *restrict l, const char *restrict filename, ks_size_t *len); -#endif - - /* ready-made comparators, meters and hash computers */ - /* comparator functions */ - /** - * ready-made comparator for int8_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_int8_t(const void *a, const void *b); - - /** - * ready-made comparator for int16_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_int16_t(const void *a, const void *b); - - /** - * ready-made comparator for int32_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_int32_t(const void *a, const void *b); - - /** - * ready-made comparator for int64_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_int64_t(const void *a, const void *b); - - /** - * ready-made comparator for uint8_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_uint8_t(const void *a, const void *b); - - /** - * ready-made comparator for uint16_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_uint16_t(const void *a, const void *b); - - /** - * ready-made comparator for uint32_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_uint32_t(const void *a, const void *b); - - /** - * ready-made comparator for uint64_t elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_uint64_t(const void *a, const void *b); - - /** - * ready-made comparator for float elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_float(const void *a, const void *b); - - /** - * ready-made comparator for double elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_double(const void *a, const void *b); - - /** - * ready-made comparator for string elements. - * @see ks_list_attributes_comparator() - */ - int ks_list_comparator_string(const void *a, const void *b); - - /* metric functions */ - /** - * ready-made metric function for int8_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_int8_t(const void *el); - - /** - * ready-made metric function for int16_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_int16_t(const void *el); - - /** - * ready-made metric function for int32_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_int32_t(const void *el); - - /** - * ready-made metric function for int64_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_int64_t(const void *el); - - /** - * ready-made metric function for uint8_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_uint8_t(const void *el); - - /** - * ready-made metric function for uint16_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_uint16_t(const void *el); - - /** - * ready-made metric function for uint32_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_uint32_t(const void *el); - - /** - * ready-made metric function for uint64_t elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_uint64_t(const void *el); - - /** - * ready-made metric function for float elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_float(const void *el); - - /** - * ready-made metric function for double elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_double(const void *el); - - /** - * ready-made metric function for string elements. - * @see ks_list_attributes_copy() - */ - ks_size_t ks_list_meter_string(const void *el); - - /* hash functions */ - /** - * ready-made hash function for int8_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_int8_t(const void *el); - - /** - * ready-made hash function for int16_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_int16_t(const void *el); - - /** - * ready-made hash function for int32_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_int32_t(const void *el); - - /** - * ready-made hash function for int64_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_int64_t(const void *el); - - /** - * ready-made hash function for uint8_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_uint8_t(const void *el); - - /** - * ready-made hash function for uint16_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_uint16_t(const void *el); - - /** - * ready-made hash function for uint32_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_uint32_t(const void *el); - - /** - * ready-made hash function for uint64_t elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_uint64_t(const void *el); - - /** - * ready-made hash function for float elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_float(const void *el); - - /** - * ready-made hash function for double elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_double(const void *el); - - /** - * ready-made hash function for string elements. - * @see ks_list_attributes_hash_computer() - */ - ks_list_hash_t ks_list_hashcomputer_string(const void *el); - -#ifdef __cplusplus -} -#endif - -#endif - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks.c b/libs/libks/src/ks.c deleted file mode 100644 index c3b3a8b297..0000000000 --- a/libs/libks/src/ks.c +++ /dev/null @@ -1,201 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - -static ks_pool_t *pool = NULL; - - - -KS_DECLARE(void) ks_random_string(char *buf, uint16_t len, char *set) -{ - char chars[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"; - int max; - uint16_t x; - - if (!set) { - set = chars; - } - - max = (int) strlen(set); - - for (x = 0; x < len; x++) { - int j = (int) (max * 1.0 * rand() / (RAND_MAX + 1.0)); - buf[x] = set[j]; - } -} - - -KS_DECLARE(ks_status_t) ks_init(void) -{ - unsigned int pid = 0; - - ks_time_init(); - -#ifdef __WINDOWS__ - pid = _getpid(); -#else - pid = getpid(); -#endif - srand(pid * (unsigned int)(intptr_t)&pool + (unsigned int)time(NULL)); - ks_ssl_init_ssl_locks(); - ks_global_pool(); - ks_rng_init(); - -#ifdef __WINDOWS__ - WSADATA wsaData; - WORD wVersionRequested = MAKEWORD(2, 2); - if (WSAStartup(wVersionRequested, &wsaData)) { - abort(); - } -#endif - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_shutdown(void) -{ - ks_status_t status = KS_STATUS_SUCCESS; - -#ifdef __WINDOWS__ - WSACleanup(); -#endif - - ks_ssl_destroy_ssl_locks(); - //ks_rng_shutdown(); - - if (pool) { - status = ks_pool_close(&pool); - } - - return status; -} - -KS_DECLARE(ks_pool_t *) ks_global_pool(void) -{ - - ks_status_t status; - - if (!pool) { - if ((status = ks_pool_open(&pool)) != KS_STATUS_SUCCESS) { - abort(); - } - } - - return pool; -} - -KS_ENUM_NAMES(STATUS_NAMES, STATUS_STRINGS) -KS_STR2ENUM(ks_str2ks_status, ks_status2str, ks_status_t, STATUS_NAMES, KS_STATUS_COUNT) - -KS_DECLARE(size_t) ks_url_encode(const char *url, char *buf, size_t len) -{ - const char *p; - size_t x = 0; - const char urlunsafe[] = "\r\n \"#%&+:;<=>?@[\\]^`{|}"; - const char hex[] = "0123456789ABCDEF"; - - if (!buf) { - return 0; - } - - if (!url) { - return 0; - } - - len--; - - for (p = url; *p; p++) { - if (x >= len) { - break; - } - if (*p < ' ' || *p > '~' || strchr(urlunsafe, *p)) { - if ((x + 3) >= len) { - break; - } - buf[x++] = '%'; - buf[x++] = hex[*p >> 4]; - buf[x++] = hex[*p & 0x0f]; - } else { - buf[x++] = *p; - } - } - buf[x] = '\0'; - - return x; -} - -KS_DECLARE(char *) ks_url_decode(char *s) -{ - char *o; - unsigned int tmp; - - for (o = s; *s; s++, o++) { - if (*s == '%' && strlen(s) > 2 && sscanf(s + 1, "%2x", &tmp) == 1) { - *o = (char) tmp; - s += 2; - } else { - *o = *s; - } - } - *o = '\0'; - return s; -} - -KS_DECLARE(int) ks_cpu_count(void) -{ - int cpu_count; - -#ifndef WIN32 - cpu_count = sysconf (_SC_NPROCESSORS_ONLN); -#else - { - SYSTEM_INFO sysinfo; - GetSystemInfo( &sysinfo ); - cpu_count = sysinfo.dwNumberOfProcessors; - } -#endif - - return cpu_count; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_acl.c b/libs/libks/src/ks_acl.c deleted file mode 100644 index 3555787298..0000000000 --- a/libs/libks/src/ks_acl.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - - -struct ks_network_node { - ks_ip_t ip; - ks_ip_t mask; - uint32_t bits; - int family; - ks_bool_t ok; - char *token; - char *str; - struct ks_network_node *next; -}; -typedef struct ks_network_node ks_network_node_t; - -struct ks_network_list { - struct ks_network_node *node_head; - ks_bool_t default_type; - char *name; -}; - - -KS_DECLARE(ks_status_t) ks_network_list_create(ks_network_list_t **list, const char *name, ks_bool_t default_type, - ks_pool_t *pool) -{ - ks_network_list_t *new_list; - - if (!pool) { - ks_pool_open(&pool); - } - - new_list = ks_pool_alloc(pool, sizeof(**list)); - new_list->default_type = default_type; - new_list->name = ks_pstrdup(pool, name); - - *list = new_list; - - return KS_STATUS_SUCCESS; -} - -#define IN6_AND_MASK(result, ip, mask) \ - ((uint32_t *) (result))[0] =((const uint32_t *) (ip))[0] & ((const uint32_t *)(mask))[0]; \ - ((uint32_t *) (result))[1] =((const uint32_t *) (ip))[1] & ((const uint32_t *)(mask))[1]; \ - ((uint32_t *) (result))[2] =((const uint32_t *) (ip))[2] & ((const uint32_t *)(mask))[2]; \ - ((uint32_t *) (result))[3] =((const uint32_t *) (ip))[3] & ((const uint32_t *)(mask))[3]; -KS_DECLARE(ks_bool_t) ks_testv6_subnet(ks_ip_t _ip, ks_ip_t _net, ks_ip_t _mask) { - if (!IN6_IS_ADDR_UNSPECIFIED(&_mask.v6)) { - struct in6_addr a, b; - IN6_AND_MASK(&a, &_net, &_mask); - IN6_AND_MASK(&b, &_ip, &_mask); - return !memcmp(&a,&b, sizeof(struct in6_addr)); - } else { - if (!IN6_IS_ADDR_UNSPECIFIED(&_net.v6)) { - return !memcmp(&_net,&_ip,sizeof(struct in6_addr)); - } - else return KS_TRUE; - } -} -KS_DECLARE(ks_bool_t) ks_network_list_validate_ip6_token(ks_network_list_t *list, ks_ip_t ip, const char **token) -{ - ks_network_node_t *node; - ks_bool_t ok = list->default_type; - uint32_t bits = 0; - - for (node = list->node_head; node; node = node->next) { - if (node->family == AF_INET) continue; - - if (node->bits >= bits && ks_testv6_subnet(ip, node->ip, node->mask)) { - if (node->ok) { - ok = KS_TRUE; - } else { - ok = KS_FALSE; - } - - bits = node->bits; - - if (token) { - *token = node->token; - } - } - } - - return ok; -} - -KS_DECLARE(ks_bool_t) ks_network_list_validate_ip_token(ks_network_list_t *list, uint32_t ip, const char **token) -{ - ks_network_node_t *node; - ks_bool_t ok = list->default_type; - uint32_t bits = 0; - - for (node = list->node_head; node; node = node->next) { - if (node->family == AF_INET6) continue; /* want AF_INET */ - if (node->bits >= bits && ks_test_subnet(ip, node->ip.v4, node->mask.v4)) { - if (node->ok) { - ok = KS_TRUE; - } else { - ok = KS_FALSE; - } - - bits = node->bits; - - if (token) { - *token = node->token; - } - } - } - - return ok; -} - -KS_DECLARE(char *) ks_network_ipv4_mapped_ipv6_addr(const char* ip_str) -{ - /* ipv4 mapped ipv6 address */ - - if (strncasecmp(ip_str, "::ffff:", 7)) { - return NULL; - } - - return strdup(ip_str + 7); -} - - -KS_DECLARE(int) ks_parse_cidr(const char *string, ks_ip_t *ip, ks_ip_t *mask, uint32_t *bitp) -{ - char host[128]; - char *bit_str; - int32_t bits; - const char *ipv6; - ks_ip_t *maskv = mask; - ks_ip_t *ipv = ip; - - ks_copy_string(host, string, sizeof(host)-1); - bit_str = strchr(host, '/'); - - if (!bit_str) { - return -1; - } - - *bit_str++ = '\0'; - bits = atoi(bit_str); - ipv6 = strchr(string, ':'); - if (ipv6) { - int i,n; - if (bits < 0 || bits > 128) { - return -2; - } - bits = atoi(bit_str); - ks_inet_pton(AF_INET6, host, (unsigned char *)ip); - for (n=bits,i=0 ;i < 16; i++){ - if (n >= 8) { - maskv->v6.s6_addr[i] = 0xFF; - n -= 8; - } else if (n < 8) { - maskv->v6.s6_addr[i] = 0xFF & ~(0xFF >> n); - n -= n; - } else if (n == 0) { - maskv->v6.s6_addr[i] = 0x00; - } - } - } else { - if (bits < 0 || bits > 32) { - return -2; - } - - bits = atoi(bit_str); - ks_inet_pton(AF_INET, host, (unsigned char *)ip); - ipv->v4 = htonl(ipv->v4); - - maskv->v4 = 0xFFFFFFFF & ~(0xFFFFFFFF >> bits); - } - *bitp = bits; - - return 0; -} - - - - -KS_DECLARE(ks_status_t) ks_network_list_perform_add_cidr_token(ks_network_list_t *list, const char *cidr_str, ks_bool_t ok, - const char *token) -{ - ks_pool_t *pool = NULL; - ks_ip_t ip, mask; - uint32_t bits; - ks_network_node_t *node; - char *ipv4 = NULL; - - if ((ipv4 = ks_network_ipv4_mapped_ipv6_addr(cidr_str))) { - cidr_str = ipv4; - } - - if (ks_parse_cidr(cidr_str, &ip, &mask, &bits)) { - ks_log(KS_LOG_ERROR, "Error Adding %s (%s) [%s] to list %s\n", - cidr_str, ok ? "allow" : "deny", ks_str_nil(token), list->name); - ks_safe_free(ipv4); - return KS_STATUS_GENERR; - } - - pool = ks_pool_get(list); - - node = ks_pool_alloc(pool, sizeof(*node)); - - node->ip = ip; - node->mask = mask; - node->ok = ok; - node->bits = bits; - node->str = ks_pstrdup(pool, cidr_str); - - if (strchr(cidr_str,':')) { - node->family = AF_INET6; - } else { - node->family = AF_INET; - } - - if (!zstr(token)) { - node->token = ks_pstrdup(pool, token); - } - - node->next = list->node_head; - list->node_head = node; - - ks_log(KS_LOG_NOTICE, "Adding %s (%s) [%s] to list %s\n", - cidr_str, ok ? "allow" : "deny", ks_str_nil(token), list->name); - - ks_safe_free(ipv4); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_network_list_add_cidr_token(ks_network_list_t *list, const char *cidr_str, ks_bool_t ok, const char *token) -{ - char *cidr_str_dup = NULL; - ks_status_t status = KS_STATUS_SUCCESS; - - if (strchr(cidr_str, ',')) { - char *argv[32] = { 0 }; - int i, argc; - cidr_str_dup = strdup(cidr_str); - - ks_assert(cidr_str_dup); - if ((argc = ks_separate_string(cidr_str_dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) { - for (i = 0; i < argc; i++) { - ks_status_t this_status; - if ((this_status = ks_network_list_perform_add_cidr_token(list, argv[i], ok, token)) != KS_STATUS_SUCCESS) { - status = this_status; - } - } - } - } else { - status = ks_network_list_perform_add_cidr_token(list, cidr_str, ok, token); - } - - ks_safe_free(cidr_str_dup); - return status; -} - -KS_DECLARE(ks_status_t) ks_network_list_add_host_mask(ks_network_list_t *list, const char *host, const char *mask_str, ks_bool_t ok) -{ - ks_pool_t *pool = NULL; - ks_ip_t ip, mask; - ks_network_node_t *node; - - ks_inet_pton(AF_INET, host, &ip); - ks_inet_pton(AF_INET, mask_str, &mask); - - pool = ks_pool_get(list); - - node = ks_pool_alloc(pool, sizeof(*node)); - - node->ip.v4 = ntohl(ip.v4); - node->mask.v4 = ntohl(mask.v4); - node->ok = ok; - - /* http://graphics.stanford.edu/~seander/bithacks.html */ - mask.v4 = mask.v4 - ((mask.v4 >> 1) & 0x55555555); - mask.v4 = (mask.v4 & 0x33333333) + ((mask.v4 >> 2) & 0x33333333); - node->bits = (((mask.v4 + (mask.v4 >> 4)) & 0xF0F0F0F) * 0x1010101) >> 24; - - node->str = ks_psprintf(pool, "%s:%s", host, mask_str); - - node->next = list->node_head; - list->node_head = node; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_bool_t) ks_check_network_list_ip_cidr(const char *ip_str, const char *cidr_str) -{ - ks_ip_t ip, mask, net; - uint32_t bits; - char *ipv6 = strchr(ip_str,':'); - ks_bool_t ok = KS_FALSE; - char *ipv4 = NULL; - - if ((ipv4 = ks_network_ipv4_mapped_ipv6_addr(ip_str))) { - ip_str = ipv4; - ipv6 = NULL; - } - - if (ipv6) { - ks_inet_pton(AF_INET6, ip_str, &ip); - } else { - ks_inet_pton(AF_INET, ip_str, &ip); - ip.v4 = htonl(ip.v4); - } - - ks_parse_cidr(cidr_str, &net, &mask, &bits); - - if (ipv6) { - ok = ks_testv6_subnet(ip, net, mask); - } else { - ok = ks_test_subnet(ip.v4, net.v4, mask.v4); - } - - ks_safe_free(ipv4); - - return ok; -} - -KS_DECLARE(ks_bool_t) ks_check_network_list_ip_token(const char *ip_str, ks_network_list_t *list, const char **token) -{ - ks_ip_t ip; - char *ipv6 = strchr(ip_str,':'); - ks_bool_t ok = KS_FALSE; - char *ipv4 = NULL; - - if ((ipv4 = ks_network_ipv4_mapped_ipv6_addr(ip_str))) { - ip_str = ipv4; - ipv6 = NULL; - } - - if (ipv6) { - ks_inet_pton(AF_INET6, ip_str, &ip); - } else { - ks_inet_pton(AF_INET, ip_str, &ip); - ip.v4 = htonl(ip.v4); - } - - - if (ipv6) { - ok = ks_network_list_validate_ip6_token(list, ip, token); - } else { - ok = ks_network_list_validate_ip_token(list, ip.v4, token); - } - - ks_safe_free(ipv4); - - return ok; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_base64.c b/libs/libks/src/ks_base64.c deleted file mode 100644 index 6e528f0fd2..0000000000 --- a/libs/libks/src/ks_base64.c +++ /dev/null @@ -1,130 +0,0 @@ -/* - * Copyright (c) 2017 FreeSWITCH Solutions 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: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - - -static const char ks_b64_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - - -KS_DECLARE(ks_status_t) ks_b64_encode(unsigned char *in, ks_size_t ilen, unsigned char *out, ks_size_t olen) -{ - int y = 0, bytes = 0; - size_t x = 0; - unsigned int b = 0, l = 0; - - for (x = 0; x < ilen; x++) { - b = (b << 8) + in[x]; - l += 8; - - while (l >= 6) { - out[bytes++] = ks_b64_table[(b >> (l -= 6)) % 64]; - if (bytes >= (int)olen - 1) { - goto end; - } - if (++y != 72) { - continue; - } - /* out[bytes++] = '\n'; */ - y = 0; - } - } - - if (l > 0) { - out[bytes++] = ks_b64_table[((b % 16) << (6 - l)) % 64]; - } - if (l != 0) { - while (l < 6 && bytes < (int)olen - 1) { - out[bytes++] = '=', l += 2; - } - } - - end: - - out[bytes] = '\0'; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_size_t) ks_b64_decode(char *in, char *out, ks_size_t olen) -{ - - char l64[256]; - int b = 0, c, l = 0, i; - char *ip, *op = out; - size_t ol = 0; - - for (i = 0; i < 256; i++) { - l64[i] = -1; - } - - for (i = 0; i < 64; i++) { - l64[(int) ks_b64_table[i]] = (char) i; - } - - for (ip = in; ip && *ip; ip++) { - c = l64[(int) *ip]; - if (c == -1) { - continue; - } - - b = (b << 6) + c; - l += 6; - - while (l >= 8) { - op[ol++] = (char) ((b >> (l -= 8)) % 256); - if (ol >= olen - 2) { - goto end; - } - } - } - - end: - - op[ol++] = '\0'; - - return ol; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_buffer.c b/libs/libks/src/ks_buffer.c deleted file mode 100644 index 1f5254c40d..0000000000 --- a/libs/libks/src/ks_buffer.c +++ /dev/null @@ -1,355 +0,0 @@ -/* - * Copyright (c) 2010-2012, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "ks.h" - -static unsigned buffer_id = 0; - -struct ks_buffer { - unsigned char *data; - unsigned char *head; - ks_size_t used; - ks_size_t actually_used; - ks_size_t datalen; - ks_size_t max_len; - ks_size_t blocksize; - unsigned id; - int loops; -}; - - -KS_DECLARE(ks_status_t) ks_buffer_create(ks_buffer_t **buffer, ks_size_t blocksize, ks_size_t start_len, ks_size_t max_len) -{ - ks_buffer_t *new_buffer; - - new_buffer = malloc(sizeof(*new_buffer)); - if (new_buffer) { - memset(new_buffer, 0, sizeof(*new_buffer)); - - if (start_len) { - new_buffer->data = malloc(start_len); - if (!new_buffer->data) { - free(new_buffer); - return KS_STATUS_FAIL; - } - memset(new_buffer->data, 0, start_len); - } - - new_buffer->max_len = max_len; - new_buffer->datalen = start_len; - new_buffer->id = buffer_id++; - new_buffer->blocksize = blocksize; - new_buffer->head = new_buffer->data; - - *buffer = new_buffer; - return KS_STATUS_SUCCESS; - } - - return KS_STATUS_FAIL; -} - -KS_DECLARE(ks_size_t) ks_buffer_len(ks_buffer_t *buffer) -{ - - ks_assert(buffer != NULL); - - return buffer->datalen; - -} - - -KS_DECLARE(ks_size_t) ks_buffer_freespace(ks_buffer_t *buffer) -{ - ks_assert(buffer != NULL); - - if (buffer->max_len) { - return (ks_size_t) (buffer->max_len - buffer->used); - } - return 1000000; - -} - -KS_DECLARE(ks_size_t) ks_buffer_inuse(ks_buffer_t *buffer) -{ - ks_assert(buffer != NULL); - - return buffer->used; -} - -KS_DECLARE(ks_size_t) ks_buffer_seek(ks_buffer_t *buffer, ks_size_t datalen) -{ - ks_size_t reading = 0; - - ks_assert(buffer != NULL); - - if (buffer->used < 1) { - buffer->used = 0; - return 0; - } else if (buffer->used >= datalen) { - reading = datalen; - } else { - reading = buffer->used; - } - - buffer->used = buffer->actually_used - reading; - buffer->head = buffer->data + reading; - - return reading; -} - -KS_DECLARE(ks_size_t) ks_buffer_toss(ks_buffer_t *buffer, ks_size_t datalen) -{ - ks_size_t reading = 0; - - ks_assert(buffer != NULL); - - if (buffer->used < 1) { - buffer->used = 0; - return 0; - } else if (buffer->used >= datalen) { - reading = datalen; - } else { - reading = buffer->used; - } - - buffer->used -= reading; - buffer->head += reading; - - return buffer->used; -} - -KS_DECLARE(void) ks_buffer_set_loops(ks_buffer_t *buffer, int loops) -{ - buffer->loops = loops; -} - -KS_DECLARE(ks_size_t) ks_buffer_read_loop(ks_buffer_t *buffer, void *data, ks_size_t datalen) -{ - ks_size_t len; - if ((len = ks_buffer_read(buffer, data, datalen)) < datalen) { - if (buffer->loops == 0) { - return len; - } - buffer->head = buffer->data; - buffer->used = buffer->actually_used; - len = ks_buffer_read(buffer, (char *) data + len, datalen - len); - buffer->loops--; - } - return len; -} - -KS_DECLARE(ks_size_t) ks_buffer_read(ks_buffer_t *buffer, void *data, ks_size_t datalen) -{ - ks_size_t reading = 0; - - ks_assert(buffer != NULL); - ks_assert(data != NULL); - - - if (buffer->used < 1) { - buffer->used = 0; - return 0; - } else if (buffer->used >= datalen) { - reading = datalen; - } else { - reading = buffer->used; - } - - memcpy(data, buffer->head, reading); - buffer->used -= reading; - buffer->head += reading; - - /* if (buffer->id == 4) printf("%u o %d = %d\n", buffer->id, (unsigned)reading, (unsigned)buffer->used); */ - return reading; -} - - -KS_DECLARE(ks_size_t) ks_buffer_packet_count(ks_buffer_t *buffer) -{ - char *pe, *p, *e, *head = (char *) buffer->head; - ks_size_t x = 0; - - ks_assert(buffer != NULL); - - e = (head + buffer->used); - - for (p = head; p && *p && p < e; p++) { - if (*p == '\n') { - pe = p + 1; - if (*pe == '\r') - pe++; - if (pe <= e && *pe == '\n') { - p = pe++; - x++; - } - } - } - - return x; -} - -KS_DECLARE(ks_size_t) ks_buffer_read_packet(ks_buffer_t *buffer, void *data, ks_size_t maxlen) -{ - char *pe, *p, *e, *head = (char *) buffer->head; - ks_size_t datalen = 0; - - ks_assert(buffer != NULL); - ks_assert(data != NULL); - - e = (head + buffer->used); - - for (p = head; p && *p && p < e; p++) { - if (*p == '\n') { - pe = p + 1; - if (*pe == '\r') - pe++; - if (pe <= e && *pe == '\n') { - pe++; - datalen = pe - head; - if (datalen > maxlen) { - datalen = maxlen; - } - break; - } - } - } - - return ks_buffer_read(buffer, data, datalen); -} - -KS_DECLARE(ks_size_t) ks_buffer_write(ks_buffer_t *buffer, const void *data, ks_size_t datalen) -{ - ks_size_t freespace, actual_freespace; - - ks_assert(buffer != NULL); - ks_assert(data != NULL); - ks_assert(buffer->data != NULL); - - if (!datalen) { - return buffer->used; - } - - actual_freespace = buffer->datalen - buffer->actually_used; - if (actual_freespace < datalen && (!buffer->max_len || (buffer->used + datalen <= buffer->max_len))) { - memmove(buffer->data, buffer->head, buffer->used); - buffer->head = buffer->data; - buffer->actually_used = buffer->used; - } - - freespace = buffer->datalen - buffer->used; - - /* - if (buffer->data != buffer->head) { - memmove(buffer->data, buffer->head, buffer->used); - buffer->head = buffer->data; - } - */ - - if (freespace < datalen) { - ks_size_t new_size, new_block_size; - void *data1; - - new_size = buffer->datalen + datalen; - new_block_size = buffer->datalen + buffer->blocksize; - - if (new_block_size > new_size) { - new_size = new_block_size; - } - buffer->head = buffer->data; - data1 = realloc(buffer->data, new_size); - if (!data1) { - return 0; - } - buffer->data = data1; - buffer->head = buffer->data; - buffer->datalen = new_size; - } - - - freespace = buffer->datalen - buffer->used; - - if (freespace < datalen) { - return 0; - } else { - memcpy(buffer->head + buffer->used, data, datalen); - buffer->used += datalen; - buffer->actually_used += datalen; - } - /* if (buffer->id == 4) printf("%u i %d = %d\n", buffer->id, (unsigned)datalen, (unsigned)buffer->used); */ - - return buffer->used; -} - -KS_DECLARE(void) ks_buffer_zero(ks_buffer_t *buffer) -{ - ks_assert(buffer != NULL); - ks_assert(buffer->data != NULL); - - buffer->used = 0; - buffer->actually_used = 0; - buffer->head = buffer->data; -} - -KS_DECLARE(ks_size_t) ks_buffer_zwrite(ks_buffer_t *buffer, const void *data, ks_size_t datalen) -{ - ks_size_t w; - - if (!(w = ks_buffer_write(buffer, data, datalen))) { - ks_buffer_zero(buffer); - return ks_buffer_write(buffer, data, datalen); - } - - return w; -} - -KS_DECLARE(void) ks_buffer_destroy(ks_buffer_t **buffer) -{ - if (*buffer) { - free((*buffer)->data); - free(*buffer); - } - - *buffer = NULL; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_config.c b/libs/libks/src/ks_config.c deleted file mode 100644 index dbde56ff73..0000000000 --- a/libs/libks/src/ks_config.c +++ /dev/null @@ -1,255 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "ks.h" - -KS_DECLARE(int) ks_config_open_file(ks_config_t *cfg, const char *file_path) -{ - FILE *f; - const char *path = NULL; - char path_buf[1024]; - - if (file_path[0] == '/') { - path = file_path; - } else { - ks_snprintf(path_buf, sizeof(path_buf), "%s%s%s", KS_CONFIG_DIR, KS_PATH_SEPARATOR, file_path); - path = path_buf; - } - - if (!path) { - return 0; - } - - memset(cfg, 0, sizeof(*cfg)); - cfg->lockto = -1; - ks_log(KS_LOG_DEBUG, "Configuration file is %s.\n", path); - f = fopen(path, "r"); - - if (!f) { - if (file_path[0] != '/') { - int last = -1; - char *var, *val; - - ks_snprintf(path_buf, sizeof(path_buf), "%s%sopenks.conf", KS_CONFIG_DIR, KS_PATH_SEPARATOR); - path = path_buf; - - if ((f = fopen(path, "r")) == 0) { - return 0; - } - - cfg->file = f; - ks_set_string(cfg->path, path); - - while (ks_config_next_pair(cfg, &var, &val)) { - if ((cfg->sectno != last) && !strcmp(cfg->section, file_path)) { - cfg->lockto = cfg->sectno; - return 1; - } - } - - ks_config_close_file(cfg); - memset(cfg, 0, sizeof(*cfg)); - return 0; - } - - return 0; - } else { - cfg->file = f; - ks_set_string(cfg->path, path); - return 1; - } -} - -KS_DECLARE(void) ks_config_close_file(ks_config_t *cfg) -{ - - if (cfg->file) { - fclose(cfg->file); - } - - memset(cfg, 0, sizeof(*cfg)); -} - - - -KS_DECLARE(int) ks_config_next_pair(ks_config_t *cfg, char **var, char **val) -{ - int ret = 0; - char *p, *end; - - *var = *val = NULL; - - if (!cfg || !cfg->file) { - return 0; - } - - for (;;) { - cfg->lineno++; - - if (!fgets(cfg->buf, sizeof(cfg->buf), cfg->file)) { - ret = 0; - break; - } - *var = cfg->buf; - - if (**var == '[' && (end = strchr(*var, ']')) != 0) { - *end = '\0'; - (*var)++; - if (**var == '+') { - (*var)++; - ks_copy_string(cfg->section, *var, sizeof(cfg->section)); - cfg->sectno++; - - if (cfg->lockto > -1 && cfg->sectno != cfg->lockto) { - break; - } - cfg->catno = 0; - cfg->lineno = 0; - *var = (char *) ""; - *val = (char *) ""; - return 1; - } else { - ks_copy_string(cfg->category, *var, sizeof(cfg->category)); - cfg->catno++; - } - continue; - } - - - - if (**var == '#' || **var == ';' || **var == '\n' || **var == '\r') { - continue; - } - - if (!strncmp(*var, "__END__", 7)) { - break; - } - - - if ((end = strchr(*var, ';')) && *(end + 1) == *end) { - *end = '\0'; - end--; - } else if ((end = strchr(*var, '\n')) != 0) { - if (*(end - 1) == '\r') { - end--; - } - *end = '\0'; - } - - p = *var; - while ((*p == ' ' || *p == '\t') && p != end) { - *p = '\0'; - p++; - } - *var = p; - - - if ((*val = strchr(*var, '=')) == 0) { - ret = -1; - /* log_printf(0, server.log, "Invalid syntax on %s: line %d\n", cfg->path, cfg->lineno); */ - continue; - } else { - p = *val - 1; - *(*val) = '\0'; - (*val)++; - if (*(*val) == '>') { - *(*val) = '\0'; - (*val)++; - } - - while ((*p == ' ' || *p == '\t') && p != *var) { - *p = '\0'; - p--; - } - - p = *val; - while ((*p == ' ' || *p == '\t') && p != end) { - *p = '\0'; - p++; - } - *val = p; - ret = 1; - break; - } - } - - - return ret; - -} - -KS_DECLARE(int) ks_config_get_cas_bits(char *strvalue, unsigned char *outbits) -{ - char cas_bits[5]; - unsigned char bit = 0x8; - char *double_colon = strchr(strvalue, ':'); - int x = 0; - - if (!double_colon) { - ks_log(KS_LOG_ERROR, "No CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon); - return -1; - } - - double_colon++; - *outbits = 0; - cas_bits[4] = 0; - - if (sscanf(double_colon, "%c%c%c%c", &cas_bits[0], &cas_bits[1], &cas_bits[2], &cas_bits[3]) != 4) { - ks_log(KS_LOG_ERROR, "Invalid CAS bits specified: %s, :xxxx definition expected, where x is 1 or 0\n", double_colon); - return -1; - } - - ks_log(KS_LOG_DEBUG, "CAS bits specification found: %s\n", cas_bits); - - for (; cas_bits[x]; x++) { - if ('1' == cas_bits[x]) { - *outbits |= bit; - } else if ('0' != cas_bits[x]) { - ks_log(KS_LOG_ERROR, "Invalid CAS pattern specified: %s, just 0 or 1 allowed for each bit\n"); - return -1; - } - bit >>= 1; - } - return 0; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_dso.c b/libs/libks/src/ks_dso.c deleted file mode 100755 index 28d5ddf54f..0000000000 --- a/libs/libks/src/ks_dso.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Cross Platform dso/dll load abstraction - * Copyright(C) 2008 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - -#include "ks.h" - -#ifdef WIN32 -#include -#include - -KS_DECLARE(ks_status_t) ks_dso_destroy(ks_dso_lib_t *lib) { - if (lib && *lib) { - FreeLibrary(*lib); - *lib = NULL; - } - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_dso_lib_t) ks_dso_open(const char *path, char **err) { - HINSTANCE lib; -#ifdef UNICODE - size_t len = strlen(path) + 1; - wchar_t *wpath = malloc(len); - - size_t converted; - mbstowcs_s(&converted, wpath, len, path, _TRUNCATE); -#else - char * wpath = path; -#endif - lib = LoadLibraryEx(wpath, NULL, 0); - - if (!lib) { - LoadLibraryEx(wpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - } - - if (!lib) { - DWORD error = GetLastError(); - char tmp[80]; - sprintf(tmp, "dll open error [%lu]\n", error); - *err = strdup(tmp); - } - -#ifdef UNICODE - free(wpath); -#endif - return lib; -} - -KS_DECLARE(void*) ks_dso_func_sym(ks_dso_lib_t lib, const char *sym, char **err) { - FARPROC func = GetProcAddress(lib, sym); - if (!func) { - DWORD error = GetLastError(); - char tmp[80]; - sprintf(tmp, "dll sym error [%lu]\n", error); - *err = strdup(tmp); - } - return (void *)(intptr_t)func; // this should really be addr - ks_dso_func_data -} - -#else - -/* -** {======================================================================== -** This is an implementation of loadlib based on the dlfcn interface. -** The dlfcn interface is available in Linux, SunOS, Solaris, IRIX, FreeBSD, -** NetBSD, AIX 4.2, HPUX 11, and probably most other Unix flavors, at least -** as an emulation layer on top of native functions. -** ========================================================================= -*/ - -#include - -KS_DECLARE(ks_status_t) ks_dso_destroy(ks_dso_lib_t *lib) { - int rc; - if (lib && *lib) { - rc = dlclose(*lib); - if (rc) { - //ks_log(KS_LOG_ERROR, "Failed to close lib %p: %s\n", *lib, dlerror()); - return KS_STATUS_FAIL; - } - //ks_log(KS_LOG_DEBUG, "lib %p was closed with success\n", *lib); - *lib = NULL; - return KS_STATUS_SUCCESS; - } - //ks_log(KS_LOG_ERROR, "Invalid pointer provided to ks_dso_destroy\n"); - return KS_STATUS_FAIL; -} - -KS_DECLARE(ks_dso_lib_t) ks_dso_open(const char *path, char **err) { - void *lib = dlopen(path, RTLD_NOW | RTLD_LOCAL); - if (lib == NULL) { - *err = strdup(dlerror()); - } - return lib; -} - -KS_DECLARE(void *) ks_dso_func_sym(ks_dso_lib_t lib, const char *sym, char **err) { - void *func = dlsym(lib, sym); - if (!func) { - *err = strdup(dlerror()); - } - return func; -} -#endif - -/* }====================================================== */ - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_hash.c b/libs/libks/src/ks_hash.c deleted file mode 100644 index 3a28fc3e31..0000000000 --- a/libs/libks/src/ks_hash.c +++ /dev/null @@ -1,695 +0,0 @@ -/* - * Copyright (c) 2002, Christopher Clark - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "ks.h" -#include "ks_hash.h" - -struct entry -{ - void *k, *v; - unsigned int h; - ks_hash_flag_t flags; - ks_hash_destructor_t destructor; - struct entry *next; -}; - -struct ks_hash_iterator { - unsigned int pos; - ks_locked_t locked; - struct entry *e; - struct ks_hash *h; -}; - -struct ks_hash { - unsigned int tablelength; - struct entry **table; - unsigned int entrycount; - unsigned int loadlimit; - unsigned int primeindex; - unsigned int (*hashfn) (void *k); - int (*eqfn) (void *k1, void *k2); - ks_hash_flag_t flags; - ks_hash_destructor_t destructor; - ks_rwl_t *rwl; - ks_mutex_t *mutex; - uint32_t readers; - ks_size_t keysize; - ks_hash_mode_t mode; -}; - -/*****************************************************************************/ - -/*****************************************************************************/ -static inline unsigned int -hash(ks_hash_t *h, void *k) -{ - unsigned int i; - - switch (h->mode) - { - case KS_HASH_MODE_ARBITRARY: - i = ks_hash_default_arbitrary(k, h->keysize, 13); - break; - case KS_HASH_MODE_INT: - case KS_HASH_MODE_INT64: - case KS_HASH_MODE_PTR: - i = h->hashfn((void *)&k); - break; - default: - i = h->hashfn(k); - break; - } - - /* Aim to protect against poor hash functions by adding logic here - * - logic taken from java 1.4 hash source */ - - i += ~(i << 9); - i ^= ((i >> 14) | (i << 18)); /* >>> */ - i += (i << 4); - i ^= ((i >> 10) | (i << 22)); /* >>> */ - - return i; -} - - -/*****************************************************************************/ -/* indexFor */ -static __inline__ unsigned int -indexFor(unsigned int tablelength, unsigned int hashvalue) { - return (hashvalue % tablelength); -} - -/* Only works if tablelength == 2^N */ -/*static inline unsigned int - indexFor(unsigned int tablelength, unsigned int hashvalue) - { - return (hashvalue & (tablelength - 1u)); - } -*/ - -/*****************************************************************************/ -//#define freekey(X) free(X) - -/* - Credit for primes table: Aaron Krowne - http://br.endernet.org/~akrowne/ - http://planetmath.org/encyclopedia/GoodKs_HashPrimes.html -*/ -static const unsigned int primes[] = { - 53, 97, 193, 389, - 769, 1543, 3079, 6151, - 12289, 24593, 49157, 98317, - 196613, 393241, 786433, 1572869, - 3145739, 6291469, 12582917, 25165843, - 50331653, 100663319, 201326611, 402653189, - 805306457, 1610612741 -}; -const unsigned int prime_table_length = sizeof(primes)/sizeof(primes[0]); -const float max_load_factor = 0.65f; - -/*****************************************************************************/ - -static void ks_hash_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - //ks_hash_t *hash = (ks_hash_t *) ptr; - - switch(action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - //ks_hash_destroy(&hash); - break; - } - -} - -KS_DECLARE(ks_status_t) ks_hash_create(ks_hash_t **hp, ks_hash_mode_t mode, ks_hash_flag_t flags, ks_pool_t *pool) -{ - return ks_hash_create_ex(hp, 16, NULL, NULL, mode, flags, NULL, pool); -} - -KS_DECLARE(void) ks_hash_set_flags(ks_hash_t *h, ks_hash_flag_t flags) -{ - h->flags = flags; -} - -KS_DECLARE(void) ks_hash_set_keysize(ks_hash_t *h, ks_size_t keysize) -{ - h->keysize = keysize; -} - -KS_DECLARE(void) ks_hash_set_destructor(ks_hash_t *h, ks_hash_destructor_t destructor) -{ - h->destructor = destructor; -} - - -KS_DECLARE(ks_status_t) -ks_hash_create_ex(ks_hash_t **hp, unsigned int minsize, - unsigned int (*hashf) (void*), - int (*eqf) (void*,void*), ks_hash_mode_t mode, ks_hash_flag_t flags, ks_hash_destructor_t destructor, ks_pool_t *pool) -{ - ks_hash_t *h; - unsigned int pindex, size = primes[0]; - ks_size_t keysize = 0; - - switch(mode) { - case KS_HASH_MODE_CASE_INSENSITIVE: - ks_assert(hashf == NULL); - hashf = ks_hash_default_ci; - break; - case KS_HASH_MODE_INT: - ks_assert(hashf == NULL); - ks_assert(eqf == NULL); - hashf = ks_hash_default_int; - eqf = ks_hash_equalkeys_int; - keysize = 4; - break; - case KS_HASH_MODE_INT64: - ks_assert(hashf == NULL); - ks_assert(eqf == NULL); - hashf = ks_hash_default_int64; - eqf = ks_hash_equalkeys_int64; - keysize = 8; - break; - case KS_HASH_MODE_PTR: - ks_assert(hashf == NULL); - ks_assert(eqf == NULL); - hashf = ks_hash_default_ptr; - eqf = ks_hash_equalkeys_ptr; - keysize = sizeof(void *); - break; - case KS_HASH_MODE_ARBITRARY: - keysize = sizeof(void *); - break; - default: - break; - } - - if ((flags & KS_HASH_FLAG_NOLOCK)) { - flags &= ~KS_HASH_FLAG_RWLOCK; - } - - ks_assert(pool); - if (!hashf) hashf = ks_hash_default; - if (!eqf) eqf = ks_hash_equalkeys; - if (!minsize) minsize = 16; - - /* Check requested ks_hash isn't too large */ - if (minsize > (1u << 30)) {*hp = NULL; return KS_STATUS_FAIL;} - /* Enforce size as prime */ - for (pindex=0; pindex < prime_table_length; pindex++) { - if (primes[pindex] > minsize) { - size = primes[pindex]; - break; - } - } - - h = (ks_hash_t *) ks_pool_alloc(pool, sizeof(ks_hash_t)); - h->flags = flags; - h->destructor = destructor; - h->keysize = keysize; - h->mode = mode; - - if ((flags & KS_HASH_FLAG_RWLOCK)) { - ks_rwl_create(&h->rwl, pool); - } - - if (!(flags & KS_HASH_FLAG_NOLOCK)) { - ks_mutex_create(&h->mutex, KS_MUTEX_FLAG_DEFAULT, pool); - } - - - if (NULL == h) abort(); /*oom*/ - - h->table = (struct entry **)ks_pool_alloc(pool, sizeof(struct entry*) * size); - - if (NULL == h->table) abort(); /*oom*/ - - //memset(h->table, 0, size * sizeof(struct entry *)); - h->tablelength = size; - h->primeindex = pindex; - h->entrycount = 0; - h->hashfn = hashf; - h->eqfn = eqf; - h->loadlimit = (unsigned int) ceil(size * max_load_factor); - - *hp = h; - - ks_pool_set_cleanup(h, NULL, ks_hash_cleanup); - - return KS_STATUS_SUCCESS; -} - -/*****************************************************************************/ -static int -ks_hash_expand(ks_hash_t *h) -{ - /* Double the size of the table to accomodate more entries */ - struct entry **newtable; - struct entry *e; - struct entry **pE; - unsigned int newsize, i, index; - /* Check we're not hitting max capacity */ - if (h->primeindex == (prime_table_length - 1)) return 0; - newsize = primes[++(h->primeindex)]; - - newtable = (struct entry **)ks_pool_alloc(ks_pool_get(h), sizeof(struct entry*) * newsize); - if (NULL != newtable) - { - memset(newtable, 0, newsize * sizeof(struct entry *)); - /* This algorithm is not 'stable'. ie. it reverses the list - * when it transfers entries between the tables */ - for (i = 0; i < h->tablelength; i++) { - while (NULL != (e = h->table[i])) { - h->table[i] = e->next; - index = indexFor(newsize,e->h); - e->next = newtable[index]; - newtable[index] = e; - } - } - ks_pool_free(&h->table); - h->table = newtable; - } - /* Plan B: realloc instead */ - else - { - newtable = (struct entry **) - ks_pool_resize(h->table, newsize * sizeof(struct entry *)); - if (NULL == newtable) { (h->primeindex)--; return 0; } - h->table = newtable; - memset(newtable[h->tablelength], 0, newsize - h->tablelength); - for (i = 0; i < h->tablelength; i++) { - for (pE = &(newtable[i]), e = *pE; e != NULL; e = *pE) { - index = indexFor(newsize,e->h); - - if (index == i) { - pE = &(e->next); - } else { - *pE = e->next; - e->next = newtable[index]; - newtable[index] = e; - } - } - } - } - h->tablelength = newsize; - h->loadlimit = (unsigned int) ceil(newsize * max_load_factor); - return -1; -} - -/*****************************************************************************/ -KS_DECLARE(unsigned int) -ks_hash_count(ks_hash_t *h) -{ - return h->entrycount; -} - -static int key_equals(ks_hash_t *h, void *k1, void *k2) -{ - switch (h->mode) - { - case KS_HASH_MODE_ARBITRARY: - return !memcmp(k1, k2, h->keysize); - case KS_HASH_MODE_INT: - case KS_HASH_MODE_INT64: - case KS_HASH_MODE_PTR: - return h->eqfn(&k1, &k2); - default: break; - } - return h->eqfn(k1, k2); -} - -static void * _ks_hash_remove(ks_hash_t *h, void *k, unsigned int hashvalue, unsigned int index) { - /* TODO: consider compacting the table when the load factor drops enough, - * or provide a 'compact' method. */ - - struct entry *e; - struct entry **pE; - void *v; - - - pE = &(h->table[index]); - e = *pE; - while (NULL != e) { - /* Check hash value to short circuit heavier comparison */ - if ((hashvalue == e->h) && (key_equals(h, k, e->k))) { - *pE = e->next; - h->entrycount--; - v = e->v; - if (e->flags & KS_HASH_FLAG_FREE_KEY) { - ks_pool_free(&e->k); - } - if (e->flags & KS_HASH_FLAG_FREE_VALUE) { - ks_pool_free(&e->v); - v = NULL; - } else if (e->destructor) { - e->destructor(e->v); - v = e->v = NULL; - } else if (h->destructor) { - h->destructor(e->v); - v = e->v = NULL; - } - ks_pool_free(&e); - return v; - } - pE = &(e->next); - e = e->next; - } - return NULL; -} - -/*****************************************************************************/ -KS_DECLARE(ks_status_t) -ks_hash_insert_ex(ks_hash_t *h, void *k, void *v, ks_hash_flag_t flags, ks_hash_destructor_t destructor) -{ - struct entry *e; - unsigned int hashvalue = hash(h, k); - unsigned int index = indexFor(h->tablelength, hashvalue); - - ks_hash_write_lock(h); - - if (!flags) { - flags = h->flags; - } - - if (flags & KS_HASH_FLAG_DUP_CHECK) { - _ks_hash_remove(h, k, hashvalue, index); - } - - if (++(h->entrycount) > h->loadlimit) - { - /* Ignore the return value. If expand fails, we should - * still try cramming just this value into the existing table - * -- we may not have memory for a larger table, but one more - * element may be ok. Next time we insert, we'll try expanding again.*/ - ks_hash_expand(h); - index = indexFor(h->tablelength, hashvalue); - } - e = (struct entry *)ks_pool_alloc(ks_pool_get(h), sizeof(struct entry)); - e->h = hashvalue; - e->k = k; - e->v = v; - e->flags = flags; - e->destructor = destructor; - e->next = h->table[index]; - h->table[index] = e; - - ks_hash_write_unlock(h); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(void) ks_hash_write_lock(ks_hash_t *h) -{ - if ((h->flags & KS_HASH_FLAG_NOLOCK)) { - return; - } else if ((h->flags & KS_HASH_FLAG_RWLOCK)) { - ks_rwl_write_lock(h->rwl); - } else { - ks_mutex_lock(h->mutex); - } -} - -KS_DECLARE(void) ks_hash_write_unlock(ks_hash_t *h) -{ - if ((h->flags & KS_HASH_FLAG_NOLOCK)) { - return; - } else if ((h->flags & KS_HASH_FLAG_RWLOCK)) { - ks_rwl_write_unlock(h->rwl); - } else { - ks_mutex_unlock(h->mutex); - } -} - -KS_DECLARE(ks_status_t) ks_hash_read_lock(ks_hash_t *h) -{ - if (!(h->flags & KS_HASH_FLAG_RWLOCK)) { - return KS_STATUS_INACTIVE; - } - - ks_rwl_read_lock(h->rwl); - - ks_mutex_lock(h->mutex); - h->readers++; - ks_mutex_unlock(h->mutex); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_hash_read_unlock(ks_hash_t *h) -{ - if (!(h->flags & KS_HASH_FLAG_RWLOCK)) { - return KS_STATUS_INACTIVE; - } - - ks_mutex_lock(h->mutex); - h->readers--; - ks_mutex_unlock(h->mutex); - - ks_rwl_read_unlock(h->rwl); - - return KS_STATUS_SUCCESS; -} - -/*****************************************************************************/ -KS_DECLARE(void *) /* returns value associated with key */ -ks_hash_search(ks_hash_t *h, void *k, ks_locked_t locked) -{ - struct entry *e; - unsigned int hashvalue, index; - void *v = NULL; - - ks_assert(locked != KS_READLOCKED || (h->flags & KS_HASH_FLAG_RWLOCK)); - - hashvalue = hash(h,k); - index = indexFor(h->tablelength,hashvalue); - - if (locked == KS_READLOCKED) { - ks_rwl_read_lock(h->rwl); - - ks_mutex_lock(h->mutex); - h->readers++; - ks_mutex_unlock(h->mutex); - } - - e = h->table[index]; - while (NULL != e) { - /* Check hash value to short circuit heavier comparison */ - if ((hashvalue == e->h) && (key_equals(h, k, e->k))) { - v = e->v; - break; - } - e = e->next; - } - - return v; -} - -/*****************************************************************************/ -KS_DECLARE(void *) /* returns value associated with key */ -ks_hash_remove(ks_hash_t *h, void *k) -{ - void *v; - unsigned int hashvalue = hash(h,k); - - ks_hash_write_lock(h); - v = _ks_hash_remove(h, k, hashvalue, indexFor(h->tablelength,hashvalue)); - ks_hash_write_unlock(h); - - return v; -} - -/*****************************************************************************/ -/* destroy */ -KS_DECLARE(void) -ks_hash_destroy(ks_hash_t **h) -{ - unsigned int i; - struct entry *e, *f; - struct entry **table = (*h)->table; - - ks_hash_write_lock(*h); - - for (i = 0; i < (*h)->tablelength; i++) { - e = table[i]; - while (NULL != e) { - f = e; e = e->next; - - if (f->flags & KS_HASH_FLAG_FREE_KEY) { - ks_pool_free(&f->k); - } - - if (f->flags & KS_HASH_FLAG_FREE_VALUE) { - ks_pool_free(&f->v); - } else if (f->destructor) { - f->destructor(f->v); - f->v = NULL; - } else if ((*h)->destructor) { - (*h)->destructor(f->v); - f->v = NULL; - } - ks_pool_free(&f); - } - } - - ks_pool_free(&(*h)->table); - ks_hash_write_unlock(*h); - if ((*h)->rwl) ks_pool_free(&(*h)->rwl); - if ((*h)->mutex) { - ks_pool_free(&(*h)->mutex); - } - ks_pool_free(&(*h)); - *h = NULL; -} - -KS_DECLARE(void) ks_hash_last(ks_hash_iterator_t **iP) -{ - ks_hash_iterator_t *i = *iP; - - if (i->locked == KS_READLOCKED) { - ks_mutex_lock(i->h->mutex); - i->h->readers--; - ks_mutex_unlock(i->h->mutex); - - ks_rwl_read_unlock(i->h->rwl); - } - - ks_pool_free(&i); - - *iP = NULL; -} - -KS_DECLARE(ks_hash_iterator_t *) ks_hash_next(ks_hash_iterator_t **iP) -{ - - ks_hash_iterator_t *i = *iP; - - if (i->e) { - if ((i->e = i->e->next) != 0) { - return i; - } else { - i->pos++; - } - } - - while(i->pos < i->h->tablelength && !i->h->table[i->pos]) { - i->pos++; - } - - if (i->pos >= i->h->tablelength) { - goto end; - } - - if ((i->e = i->h->table[i->pos]) != 0) { - return i; - } - - end: - - ks_hash_last(iP); - - return NULL; -} - -KS_DECLARE(ks_hash_iterator_t *) ks_hash_first(ks_hash_t *h, ks_locked_t locked) -{ - ks_hash_iterator_t *iterator; - - ks_assert(locked != KS_READLOCKED || (h->flags & KS_HASH_FLAG_RWLOCK)); - - iterator = ks_pool_alloc(ks_pool_get(h), sizeof(*iterator)); - ks_assert(iterator); - - iterator->pos = 0; - iterator->e = NULL; - iterator->h = h; - - if (locked == KS_READLOCKED) { - ks_rwl_read_lock(h->rwl); - iterator->locked = locked; - ks_mutex_lock(h->mutex); - h->readers++; - ks_mutex_unlock(h->mutex); - } - - return ks_hash_next(&iterator); -} - -KS_DECLARE(void) ks_hash_this_val(ks_hash_iterator_t *i, void *val) -{ - if (i->e) { - i->e->v = val; - } -} - -KS_DECLARE(void) ks_hash_this(ks_hash_iterator_t *i, const void **key, ks_ssize_t *klen, void **val) -{ - if (i->e) { - if (key) { - *key = i->e->k; - } - if (klen) { - *klen = (int)strlen(i->e->k); - } - if (val) { - *val = i->e->v; - } - } else { - if (key) { - *key = NULL; - } - if (klen) { - *klen = 0; - } - if (val) { - *val = NULL; - } - } -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ - diff --git a/libs/libks/src/ks_json.c b/libs/libks/src/ks_json.c deleted file mode 100644 index 47e1b80861..0000000000 --- a/libs/libks/src/ks_json.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "ks.h" - -KS_DECLARE(cJSON *) cJSON_CreateStringPrintf(const char *fmt, ...) -{ - va_list ap; - char *str; - cJSON *item; - - va_start(ap, fmt); - str = ks_vmprintf(fmt, ap); - va_end(ap); - - if (!str) return NULL; - - item = cJSON_CreateString(str); - - free(str); - - return item; -} - -KS_DECLARE(const char *) cJSON_GetObjectCstr(const cJSON *object, const char *string) -{ - cJSON *cj = cJSON_GetObjectItem(object, string); - - if (!cj || cj->type != cJSON_String || !cj->valuestring) return NULL; - - return cj->valuestring; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_log.c b/libs/libks/src/ks_log.c deleted file mode 100644 index cdcbc41b2e..0000000000 --- a/libs/libks/src/ks_log.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - -static void null_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) -{ - if (file && func && line && level && fmt) { - return; - } - return; -} - - -static const char *LEVEL_NAMES[] = { - "EMERG", - "ALERT", - "CRIT", - "ERROR", - "WARNING", - "NOTICE", - "INFO", - "DEBUG", - NULL -}; - -static int ks_log_level = 7; -static ks_log_prefix_t ks_log_prefix = KS_LOG_PREFIX_ALL; - -static const char *cut_path(const char *in) -{ - const char *p, *ret = in; - char delims[] = "/\\"; - char *i; - - for (i = delims; *i; i++) { - p = in; - while ((p = strchr(p, *i)) != 0) { - ret = ++p; - } - } - return ret; -} - - -static void default_logger(const char *file, const char *func, int line, int level, const char *fmt, ...) -{ - const char *fp; - char *data; - va_list ap; - int ret; - char buf[1024]; - //int remaining = sizeof(buf) - 1; - int used = 0; - - if (level < 0 || level > 7) { - level = 7; - } - if (level > ks_log_level) { - return; - } - - fp = cut_path(file); - - va_start(ap, fmt); - - ret = ks_vasprintf(&data, fmt, ap); - - if (ret != -1) { - buf[0] = '\0'; - used += 1; - - if (ks_log_prefix & KS_LOG_PREFIX_LEVEL) { - used += snprintf(buf + used - 1, sizeof(buf) - used, "[%s] ", LEVEL_NAMES[level]); - } - if (ks_log_prefix & KS_LOG_PREFIX_TIME) { - used += snprintf(buf + used - 1, sizeof(buf) - used, "@%lld ", (long long int)ks_time_now()); - } - if (ks_log_prefix & KS_LOG_PREFIX_THREAD) { - used += snprintf(buf + used - 1, sizeof(buf) - used, "#%d ", (int32_t)ks_thread_self_id()); - } - if (ks_log_prefix & KS_LOG_PREFIX_FILE) { - used += snprintf(buf + used - 1, sizeof(buf) - used, "%s", fp); - if (ks_log_prefix & KS_LOG_PREFIX_LINE) { - used += snprintf(buf + used - 1, sizeof(buf) - used, ":%d", line); - } - used += snprintf(buf + used - 1, sizeof(buf) - used, " "); - } - if (ks_log_prefix & KS_LOG_PREFIX_FUNC) { - used += snprintf(buf + used - 1, sizeof(buf) - used, "%s() ", func); - } - - used += snprintf(buf + used - 1, sizeof(buf) - used, "%s", data); - - //fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], fp, line, func, data); - fprintf(stderr, "%s", buf); - free(data); - } - - va_end(ap); - -} - -ks_logger_t ks_logger = null_logger; - -KS_DECLARE(void) ks_global_set_logger(ks_logger_t logger) -{ - if (logger) { - ks_logger = logger; - } else { - ks_logger = null_logger; - } -} - -KS_DECLARE(void) ks_global_set_default_logger(int level) -{ - if (level < 0 || level > 7) { - level = 7; - } - - ks_logger = default_logger; - ks_log_level = level; -} - -KS_DECLARE(void) ks_global_set_default_logger_prefix(ks_log_prefix_t prefix) -{ - ks_log_prefix = prefix; -} - -KS_DECLARE(void) ks_log(const char *file, const char *func, int line, int level, const char *fmt, ...) -{ - char *data; - va_list ap; - - if (!ks_logger) return; - - va_start(ap, fmt); - - if (ks_vasprintf(&data, fmt, ap) != -1) { - ks_logger(file, func, line, level, "%s", data); - //fprintf(stderr, "[%s] %s:%d %s() %s", LEVEL_NAMES[level], fp, line, func, data); - //fprintf(stderr, "%s", buf); - free(data); - } - - va_end(ap); -} diff --git a/libs/libks/src/ks_mutex.c b/libs/libks/src/ks_mutex.c deleted file mode 100644 index 860302e818..0000000000 --- a/libs/libks/src/ks_mutex.c +++ /dev/null @@ -1,676 +0,0 @@ -/* - * Cross Platform Thread/Mutex abstraction - * Copyright(C) 2007 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - -#include "ks.h" - -#ifdef WIN32 -#include -#else -#include -#endif - -typedef enum { - KS_MUTEX_TYPE_DEFAULT, - KS_MUTEX_TYPE_NON_RECURSIVE -} ks_mutex_type_t; - -struct ks_mutex { -#ifdef WIN32 - CRITICAL_SECTION mutex; - HANDLE handle; -#else - pthread_mutex_t mutex; -#endif - ks_mutex_type_t type; - uint8_t malloc; -}; - -static void ks_mutex_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - ks_mutex_t *mutex = (ks_mutex_t *) ptr; - - switch(action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: -#ifdef WIN32 - if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) { - CloseHandle(mutex->handle); - } else { - DeleteCriticalSection(&mutex->mutex); - } -#else - pthread_mutex_destroy(&mutex->mutex); -#endif - break; - } -} - -KS_DECLARE(ks_status_t) ks_mutex_destroy(ks_mutex_t **mutexP) -{ - ks_mutex_t *mutex; - - ks_assert(mutexP); - - mutex = *mutexP; - *mutexP = NULL; - - if (!mutex) return KS_STATUS_FAIL; - - if (mutex->malloc) { -#ifdef WIN32 - if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) { - CloseHandle(mutex->handle); - } else { - DeleteCriticalSection(&mutex->mutex); - } -#else - pthread_mutex_destroy(&mutex->mutex); -#endif - free(mutex); - } else { - ks_pool_free(&mutex); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_mutex_create(ks_mutex_t **mutex, unsigned int flags, ks_pool_t *pool) -{ - ks_status_t status = KS_STATUS_FAIL; -#ifndef WIN32 - pthread_mutexattr_t attr; -#endif - ks_mutex_t *check = NULL; - - if (pool) { - if (!(check = (ks_mutex_t *) ks_pool_alloc(pool, sizeof(**mutex)))) { - goto done; - } - } else { - check = malloc(sizeof(**mutex)); - memset(check, 0, sizeof(**mutex)); - check->malloc = 1; - } - - check->type = KS_MUTEX_TYPE_DEFAULT; - -#ifdef WIN32 - if (flags & KS_MUTEX_FLAG_NON_RECURSIVE) { - check->type = KS_MUTEX_TYPE_NON_RECURSIVE; - check->handle = CreateEvent(NULL, FALSE, TRUE, NULL); - } else { - InitializeCriticalSection(&check->mutex); - } -#else - if (flags & KS_MUTEX_FLAG_NON_RECURSIVE) { - if (pthread_mutex_init(&check->mutex, NULL)) - goto done; - - } else { - if (pthread_mutexattr_init(&attr)) - goto done; - - if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE)) - goto fail; - - if (pthread_mutex_init(&check->mutex, &attr)) - goto fail; - } - - goto success; - - fail: - pthread_mutexattr_destroy(&attr); - goto done; - - success: -#endif - *mutex = check; - status = KS_STATUS_SUCCESS; - - if (pool) { - ks_pool_set_cleanup(check, NULL, ks_mutex_cleanup); - } - - done: - return status; -} - -KS_DECLARE(ks_status_t) ks_mutex_lock(ks_mutex_t *mutex) -{ -#ifdef WIN32 - if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) { - DWORD ret = WaitForSingleObject(mutex->handle, INFINITE); - if ((ret != WAIT_OBJECT_0) && (ret != WAIT_ABANDONED)) { - return KS_STATUS_FAIL; - } - } else { - EnterCriticalSection(&mutex->mutex); - } -#else - if (pthread_mutex_lock(&mutex->mutex)) - return KS_STATUS_FAIL; -#endif - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_mutex_trylock(ks_mutex_t *mutex) -{ -#ifdef WIN32 - if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) { - DWORD ret = WaitForSingleObject(mutex->handle, 0); - if ((ret != WAIT_OBJECT_0) && (ret != WAIT_ABANDONED)) { - return KS_STATUS_FAIL; - } - } else { - if (!TryEnterCriticalSection(&mutex->mutex)) - return KS_STATUS_FAIL; - } -#else - if (pthread_mutex_trylock(&mutex->mutex)) - return KS_STATUS_FAIL; -#endif - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_mutex_unlock(ks_mutex_t *mutex) -{ -#ifdef WIN32 - if (mutex->type == KS_MUTEX_TYPE_NON_RECURSIVE) { - if (!SetEvent(mutex->handle)) { - return KS_STATUS_FAIL; - } - } else { - LeaveCriticalSection(&mutex->mutex); - } -#else - if (pthread_mutex_unlock(&mutex->mutex)) - return KS_STATUS_FAIL; -#endif - return KS_STATUS_SUCCESS; -} - - - -struct ks_cond { - ks_mutex_t *mutex; -#ifdef WIN32 - CONDITION_VARIABLE cond; -#else - pthread_cond_t cond; -#endif - uint8_t static_mutex; -}; - -static void ks_cond_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - ks_cond_t *cond = (ks_cond_t *) ptr; - - switch(action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - if (!cond->static_mutex) { - ks_mutex_destroy(&cond->mutex); - } -#ifndef WIN32 - pthread_cond_destroy(&cond->cond); -#endif - break; - } -} - -KS_DECLARE(ks_status_t) ks_cond_create_ex(ks_cond_t **cond, ks_pool_t *pool, ks_mutex_t *mutex) -{ - ks_status_t status = KS_STATUS_FAIL; - ks_cond_t *check = NULL; - - *cond = NULL; - - if (!pool) - goto done; - - if (!(check = (ks_cond_t *) ks_pool_alloc(pool, sizeof(**cond)))) { - goto done; - } - - if (mutex) { - check->mutex = mutex; - check->static_mutex = 1; - } else { - if (ks_mutex_create(&check->mutex, KS_MUTEX_FLAG_DEFAULT, pool) != KS_STATUS_SUCCESS) { - goto done; - } - } - -#ifdef WIN32 - InitializeConditionVariable(&check->cond); -#else - if (pthread_cond_init(&check->cond, NULL)) { - if (!check->static_mutex) { - ks_mutex_destroy(&check->mutex); - } - goto done; - } -#endif - - *cond = check; - status = KS_STATUS_SUCCESS; - ks_pool_set_cleanup(check, NULL, ks_cond_cleanup); - - done: - return status; -} - -KS_DECLARE(ks_mutex_t *) ks_cond_get_mutex(ks_cond_t *cond) -{ - return cond->mutex; -} - -KS_DECLARE(ks_status_t) ks_cond_create(ks_cond_t **cond, ks_pool_t *pool) -{ - return ks_cond_create_ex(cond, pool, NULL); -} - -KS_DECLARE(ks_status_t) ks_cond_lock(ks_cond_t *cond) -{ - return ks_mutex_lock(cond->mutex); -} - -KS_DECLARE(ks_status_t) ks_cond_trylock(ks_cond_t *cond) -{ - return ks_mutex_trylock(cond->mutex); -} - -KS_DECLARE(ks_status_t) ks_cond_unlock(ks_cond_t *cond) -{ - return ks_mutex_unlock(cond->mutex); -} - -KS_DECLARE(ks_status_t) ks_cond_signal(ks_cond_t *cond) -{ - ks_cond_lock(cond); -#ifdef WIN32 - WakeConditionVariable(&cond->cond); -#else - pthread_cond_signal(&cond->cond); -#endif - ks_cond_unlock(cond); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_cond_broadcast(ks_cond_t *cond) -{ - ks_cond_lock(cond); -#ifdef WIN32 - WakeAllConditionVariable(&cond->cond); -#else - pthread_cond_broadcast(&cond->cond); -#endif - ks_cond_unlock(cond); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_cond_try_signal(ks_cond_t *cond) -{ - if (ks_cond_trylock(cond) != KS_STATUS_SUCCESS) { - return KS_STATUS_FAIL; - } -#ifdef WIN32 - WakeConditionVariable(&cond->cond); -#else - pthread_cond_signal(&cond->cond); -#endif - ks_cond_unlock(cond); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_cond_try_broadcast(ks_cond_t *cond) -{ - if (ks_cond_trylock(cond) != KS_STATUS_SUCCESS) { - return KS_STATUS_FAIL; - } -#ifdef WIN32 - WakeAllConditionVariable(&cond->cond); -#else - pthread_cond_broadcast(&cond->cond); -#endif - ks_cond_unlock(cond); - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_cond_wait(ks_cond_t *cond) -{ -#ifdef WIN32 - SleepConditionVariableCS(&cond->cond, &cond->mutex->mutex, INFINITE); -#else - pthread_cond_wait(&cond->cond, &cond->mutex->mutex); -#endif - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_cond_timedwait(ks_cond_t *cond, ks_time_t ms) -{ -#ifdef WIN32 - BOOL res = SleepConditionVariableCS(&cond->cond, &cond->mutex->mutex, (DWORD)ms); - if (!res) { - if (GetLastError() == ERROR_TIMEOUT) { - return KS_STATUS_TIMEOUT; - } else { - return KS_STATUS_FAIL; - } - } -#else - struct timespec ts; - ks_time_t n = ks_time_now() + (ms * 1000); - int r = 0; - - ts.tv_sec = ks_time_sec(n); - ts.tv_nsec = ks_time_nsec(n); - r = pthread_cond_timedwait(&cond->cond, &cond->mutex->mutex, &ts); - - if (r) { - switch(r) { - case ETIMEDOUT: - return KS_STATUS_TIMEOUT; - default: - return KS_STATUS_FAIL; - } - } -#endif - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_cond_destroy(ks_cond_t **cond) -{ - ks_cond_t *condp = *cond; - - if (!condp) { - return KS_STATUS_FAIL; - } - - *cond = NULL; - - return ks_pool_free(&condp); -} - - -struct ks_rwl { -#ifdef WIN32 - SRWLOCK rwlock; - ks_hash_t *read_lock_list; - ks_mutex_t *read_lock_mutex; - ks_mutex_t *write_lock_mutex; -#else - pthread_rwlock_t rwlock; -#endif - ks_pid_t write_locker; - uint32_t wlc; -}; - -static void ks_rwl_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ -#ifndef WIN32 - ks_rwl_t *rwlock = (ks_rwl_t *) ptr; -#endif - - switch(action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: -#ifndef WIN32 - pthread_rwlock_destroy(&rwlock->rwlock); -#endif - break; - } -} - -KS_DECLARE(ks_status_t) ks_rwl_create(ks_rwl_t **rwlock, ks_pool_t *pool) -{ - ks_status_t status = KS_STATUS_FAIL; - ks_rwl_t *check = NULL; - *rwlock = NULL; - - if (!pool) { - goto done; - } - - if (!(check = (ks_rwl_t *) ks_pool_alloc(pool, sizeof(**rwlock)))) { - goto done; - } - -#ifdef WIN32 - - if (ks_hash_create(&check->read_lock_list, KS_HASH_MODE_PTR, KS_HASH_FLAG_NONE, pool) != KS_STATUS_SUCCESS) { - goto done; - } - - if (ks_mutex_create(&check->read_lock_mutex, KS_MUTEX_FLAG_DEFAULT, pool) != KS_STATUS_SUCCESS) { - goto done; - } - - if (ks_mutex_create(&check->write_lock_mutex, KS_MUTEX_FLAG_DEFAULT, pool) != KS_STATUS_SUCCESS) { - goto done; - } - - InitializeSRWLock(&check->rwlock); -#else - if ((pthread_rwlock_init(&check->rwlock, NULL))) { - goto done; - } -#endif - - *rwlock = check; - status = KS_STATUS_SUCCESS; - ks_pool_set_cleanup(check, NULL, ks_rwl_cleanup); - done: - return status; -} - -KS_DECLARE(ks_status_t) ks_rwl_read_lock(ks_rwl_t *rwlock) -{ -#ifdef WIN32 - - ks_mutex_lock(rwlock->write_lock_mutex); - ks_mutex_lock(rwlock->read_lock_mutex); - - int count = (int)(intptr_t)ks_hash_remove(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id()); - - if (count) { - ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id(), (void *)(intptr_t)++count); - ks_mutex_unlock(rwlock->read_lock_mutex); - ks_mutex_unlock(rwlock->write_lock_mutex); - return KS_STATUS_SUCCESS; - } - - AcquireSRWLockShared(&rwlock->rwlock); -#else - pthread_rwlock_rdlock(&rwlock->rwlock); -#endif - -#ifdef WIN32 - ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id(), (void *)(intptr_t)(int)1); - ks_mutex_unlock(rwlock->read_lock_mutex); - ks_mutex_unlock(rwlock->write_lock_mutex); -#endif - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_rwl_write_lock(ks_rwl_t *rwlock) -{ - - int me = (rwlock->write_locker == ks_thread_self_id()); - - if (me) { - rwlock->wlc++; - return KS_STATUS_SUCCESS; - } - -#ifdef WIN32 - ks_mutex_lock(rwlock->write_lock_mutex); - AcquireSRWLockExclusive(&rwlock->rwlock); -#else - pthread_rwlock_wrlock(&rwlock->rwlock); -#endif - rwlock->write_locker = ks_thread_self_id(); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_rwl_try_read_lock(ks_rwl_t *rwlock) -{ -#ifdef WIN32 - if (ks_mutex_trylock(rwlock->write_lock_mutex) != KS_STATUS_SUCCESS) { - return KS_STATUS_FAIL; - } - - ks_mutex_lock(rwlock->read_lock_mutex); - - int count = (int)(intptr_t)ks_hash_remove(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id()); - - if (count) { - ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id(), (void *)(intptr_t)++count); - ks_mutex_unlock(rwlock->read_lock_mutex); - ks_mutex_unlock(rwlock->write_lock_mutex); - return KS_STATUS_SUCCESS; - } - - if (!TryAcquireSRWLockShared(&rwlock->rwlock)) { - ks_mutex_unlock(rwlock->read_lock_mutex); - ks_mutex_unlock(rwlock->write_lock_mutex); - return KS_STATUS_FAIL; - } -#else - if (pthread_rwlock_tryrdlock(&rwlock->rwlock)) { - return KS_STATUS_FAIL; - } -#endif - -#ifdef WIN32 - ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id(), (void *)(intptr_t)(int)1); - ks_mutex_unlock(rwlock->read_lock_mutex); - ks_mutex_unlock(rwlock->write_lock_mutex); -#endif - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_rwl_try_write_lock(ks_rwl_t *rwlock) -{ - int me = (rwlock->write_locker == ks_thread_self_id()); - - if (me) { - rwlock->wlc++; - return KS_STATUS_SUCCESS; - } - -#ifdef WIN32 - if (!TryAcquireSRWLockExclusive(&rwlock->rwlock)) { - return KS_STATUS_FAIL; - } -#else - if (pthread_rwlock_trywrlock(&rwlock->rwlock)) { - return KS_STATUS_FAIL; - } -#endif - - rwlock->write_locker = ks_thread_self_id(); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_rwl_read_unlock(ks_rwl_t *rwlock) -{ -#ifdef WIN32 - ks_mutex_lock(rwlock->read_lock_mutex); - - int count = (int)(intptr_t)ks_hash_remove(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id()); - - if (count > 1) { - ks_hash_insert(rwlock->read_lock_list, (void *)(intptr_t)ks_thread_self_id(), (void *)(intptr_t)--count); - ks_mutex_unlock(rwlock->read_lock_mutex); - return KS_STATUS_SUCCESS; - } - - ReleaseSRWLockShared(&rwlock->rwlock); - ks_mutex_unlock(rwlock->read_lock_mutex); -#else - pthread_rwlock_unlock(&rwlock->rwlock); -#endif - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_rwl_write_unlock(ks_rwl_t *rwlock) -{ - int me = (rwlock->write_locker == ks_thread_self_id()); - - if (me && rwlock->wlc > 0) { - rwlock->wlc--; - return KS_STATUS_SUCCESS; - } - - rwlock->write_locker = 0; - -#ifdef WIN32 - ReleaseSRWLockExclusive(&rwlock->rwlock); - ks_mutex_unlock(rwlock->write_lock_mutex); -#else - pthread_rwlock_unlock(&rwlock->rwlock); -#endif - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_rwl_destroy(ks_rwl_t **rwlock) -{ - ks_rwl_t *rwlockp = *rwlock; - - - if (!rwlockp) { - return KS_STATUS_FAIL; - } - - *rwlock = NULL; - - return ks_pool_free(&rwlockp); -} - - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_pool.c b/libs/libks/src/ks_pool.c deleted file mode 100644 index b030d39653..0000000000 --- a/libs/libks/src/ks_pool.c +++ /dev/null @@ -1,1301 +0,0 @@ -/* - * Memory pool routines. - * - * Copyright 1996 by Gray Watson. - * - * This file is part of the ks_pool package. - * - * Permission to use, copy, modify, and distribute this software for - * any purpose and without fee is hereby granted, provided that the - * above copyright notice and this permission notice appear in all - * copies, and that the name of Gray Watson not be used in advertising - * or publicity pertaining to distribution of the document or software - * without specific, written prior permission. - * - * Gray Watson makes no representations about the suitability of the - * software described herein for any purpose. It is provided "as is" - * without express or implied warranty. - * - * The author may be reached via http://256.com/gray/ - * - * $Id: ks_mpool.c,v 1.5 2006/05/31 20:28:31 gray Exp $ - */ - -/* - * Memory-pool allocation routines. I got sick of the GNU mmalloc - * library which was close to what we needed but did not exactly do - * what I wanted. - * - */ - -#include "ks.h" - - //#define DEBUG 1 - -#define KS_POOL_MAGIC 0xDEADBEEF /* magic for struct */ - -#define KS_POOL_PREFIX_MAGIC 0xDEADBEEF - -#define KS_POOL_FENCE_MAGIC0 (ks_byte_t)(0xFAU) /* 1st magic mem byte */ -#define KS_POOL_FENCE_MAGIC1 (ks_byte_t)(0xD3U) /* 2nd magic mem byte */ - -#define KS_POOL_FENCE_SIZE 2 /* fence space */ - -typedef struct ks_pool_prefix_s ks_pool_prefix_t; - -struct ks_pool_prefix_s { - ks_size_t magic1; - ks_size_t size; - ks_size_t magic2; - ks_size_t refs; - ks_pool_prefix_t *prev; - ks_pool_prefix_t *next; - ks_size_t magic3; - ks_pool_cleanup_callback_t cleanup_callback; - void *cleanup_arg; - ks_size_t magic4; - ks_pool_t *pool; - ks_size_t magic5; -}; - -#define KS_POOL_PREFIX_SIZE sizeof(ks_pool_prefix_t) - -#define SET_POINTER(pnt, val) \ - do { \ - if ((pnt) != NULL) { \ - (*(pnt)) = (val); \ - } \ - } while(0) - -struct ks_pool_s { - ks_size_t magic1; /* magic number for struct */ - ks_size_t flags; /* flags for the struct */ - ks_size_t alloc_c; /* number of allocations */ - ks_size_t user_alloc; /* user bytes allocated */ - ks_size_t max_alloc; /* maximum user bytes allocated */ - ks_pool_log_func_t log_func; /* log callback function */ - ks_pool_prefix_t *first; /* first memory allocation we are using */ - ks_pool_prefix_t *last; /* last memory allocation we are using */ - ks_size_t magic2; /* upper magic for overwrite sanity */ - ks_mutex_t *mutex; - ks_bool_t cleaning_up; -}; - -static ks_status_t check_pool(const ks_pool_t *pool); -static ks_status_t check_fence(const void *addr); -static void write_fence(void *addr); -static ks_status_t check_prefix(const ks_pool_prefix_t *prefix); - -static void perform_pool_cleanup_on_free(ks_pool_prefix_t *prefix) -{ - void *addr; - - ks_assert(prefix); - ks_assert(prefix->pool); - - if (prefix->pool->cleaning_up) return; - - addr = (void *)((uintptr_t)prefix + KS_POOL_PREFIX_SIZE); - - if (prefix->cleanup_callback) { - prefix->cleanup_callback(addr, prefix->cleanup_arg, KS_MPCL_ANNOUNCE, KS_MPCL_FREE); - prefix->cleanup_callback(addr, prefix->cleanup_arg, KS_MPCL_TEARDOWN, KS_MPCL_FREE); - prefix->cleanup_callback(addr, prefix->cleanup_arg, KS_MPCL_DESTROY, KS_MPCL_FREE); - } -} - -static void perform_pool_cleanup(ks_pool_t *pool) -{ - ks_pool_prefix_t *prefix; - - if (pool->cleaning_up) { - return; - } - pool->cleaning_up = KS_TRUE; - - for (prefix = pool->first; prefix; prefix = prefix->next) { - if (!prefix->cleanup_callback) continue; - prefix->cleanup_callback((void *)((uintptr_t)prefix + KS_POOL_PREFIX_SIZE), prefix->cleanup_arg, KS_MPCL_ANNOUNCE, KS_MPCL_GLOBAL_FREE); - } - - for (prefix = pool->first; prefix; prefix = prefix->next) { - if (!prefix->cleanup_callback) continue; - prefix->cleanup_callback((void *)((uintptr_t)prefix + KS_POOL_PREFIX_SIZE), prefix->cleanup_arg, KS_MPCL_TEARDOWN, KS_MPCL_GLOBAL_FREE); - } - - for (prefix = pool->first; prefix; prefix = prefix->next) { - if (!prefix->cleanup_callback) continue; - prefix->cleanup_callback((void *)((uintptr_t)prefix + KS_POOL_PREFIX_SIZE), prefix->cleanup_arg, KS_MPCL_DESTROY, KS_MPCL_GLOBAL_FREE); - } -} - -KS_DECLARE(ks_status_t) ks_pool_set_cleanup(void *ptr, void *arg, ks_pool_cleanup_callback_t callback) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_prefix_t *prefix = NULL; - - ks_assert(ptr); - ks_assert(callback); - - prefix = (ks_pool_prefix_t *)((uintptr_t)ptr - KS_POOL_PREFIX_SIZE); - - ret = check_prefix(prefix); - - if (ret == KS_STATUS_SUCCESS) { - prefix->cleanup_arg = arg; - prefix->cleanup_callback = callback; - } - - return ret; -} - - - -/****************************** local utilities ******************************/ - -/* -* static ks_status_t check_pool -* -* DESCRIPTION: -* -* Check the validity of pool checksums. -* -* RETURNS: -* -* Success - KS_STATUS_SUCCESS -* -* Failure - Ks_Pool error code -* -* ARGUMENTS: -* -* pool -> A pointer to a pool. -*/ -static ks_status_t check_pool(const ks_pool_t *pool) -{ - ks_assert(pool); - - if (pool->magic1 != KS_POOL_MAGIC) return KS_STATUS_PNT; - if (pool->magic2 != KS_POOL_MAGIC) return KS_STATUS_POOL_OVER; - - return KS_STATUS_SUCCESS; -} - -/* - * static ks_status_t check_fence - * - * DESCRIPTION: - * - * Check the validity of the fence checksums. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - Ks_Pool error code - * - * ARGUMENTS: - * - * addr -> A pointer directly to the fence. - */ -static ks_status_t check_fence(const void *addr) -{ - const ks_byte_t *mem_p; - - mem_p = (ks_byte_t *)addr; - - if (*mem_p == KS_POOL_FENCE_MAGIC0 && *(mem_p + 1) == KS_POOL_FENCE_MAGIC1) return KS_STATUS_SUCCESS; - return KS_STATUS_PNT_OVER; -} - -/* - * static void write_fence - * - * DESCRIPTION: - * - * Write the magic ID to the address. - * - * RETURNS: - * - * None. - * - * ARGUMENTS: - * - * addr -> Address where to write the magic. - */ -static void write_fence(void *addr) -{ - *((ks_byte_t *)addr) = KS_POOL_FENCE_MAGIC0; - *((ks_byte_t *)addr + 1) = KS_POOL_FENCE_MAGIC1; -} - -/* -* static ks_status_t check_prefix -* -* DESCRIPTION: -* -* Check the validity of prefix checksums. -* -* RETURNS: -* -* Success - KS_STATUS_SUCCESS -* -* Failure - Ks_Pool error code -* -* ARGUMENTS: -* -* prefix -> A pointer to a prefix. -*/ -static ks_status_t check_prefix(const ks_pool_prefix_t *prefix) -{ - if (!(prefix->magic1 == KS_POOL_PREFIX_MAGIC && - prefix->magic2 == KS_POOL_PREFIX_MAGIC && - prefix->magic3 == KS_POOL_PREFIX_MAGIC && - prefix->magic4 == KS_POOL_PREFIX_MAGIC && - prefix->magic5 == KS_POOL_PREFIX_MAGIC)) return KS_STATUS_INVALID_POINTER; - return KS_STATUS_SUCCESS; -} - -/* - * static void *alloc_mem - * - * DESCRIPTION: - * - * Allocate space for bytes inside of an already open memory pool. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * byte_size -> Number of bytes to allocate in the pool. Must be >0. - * - * error_p <- Pointer to ks_status_t which, if not NULL, will be set with - * a ks_pool error code. - */ -static void *alloc_mem(ks_pool_t *pool, const ks_size_t size, ks_status_t *error_p) -{ - ks_size_t required; - void *start = NULL; - void *addr = NULL; - void *fence = NULL; - ks_pool_prefix_t *prefix = NULL; - - ks_assert(pool); - ks_assert(size); - - required = KS_POOL_PREFIX_SIZE + size + KS_POOL_FENCE_SIZE; - start = malloc(required); - ks_assert(start); - memset(start, 0, required); // @todo consider readding the NO_ZERO flag option, which would reduce this to only zero out PREFIX_SIZE instead of the entire allocation. - - prefix = (ks_pool_prefix_t *)start; - addr = (void *)((ks_byte_t *)start + KS_POOL_PREFIX_SIZE); - fence = (void *)((ks_byte_t *)addr + size); - - prefix->magic1 = KS_POOL_PREFIX_MAGIC; - prefix->size = size; - prefix->magic2 = KS_POOL_PREFIX_MAGIC; - prefix->refs = 1; - prefix->next = pool->first; - if (pool->first) pool->first->prev = prefix; - pool->first = prefix; - if (!pool->last) pool->last = prefix; - prefix->magic3 = KS_POOL_PREFIX_MAGIC; - prefix->magic4 = KS_POOL_PREFIX_MAGIC; - prefix->pool = pool; - prefix->magic5 = KS_POOL_PREFIX_MAGIC; - - write_fence(fence); - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_INCREF, prefix->size, prefix->refs, NULL, addr, 0); - } - - pool->alloc_c++; - pool->user_alloc += prefix->size; - if (pool->user_alloc > pool->max_alloc) { - pool->max_alloc = pool->user_alloc; - } - - SET_POINTER(error_p, KS_STATUS_SUCCESS); - return addr; -} - -/* - * static int free_mem - * - * DESCRIPTION: - * - * Free an address from a memory pool. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - Ks_Pool error code - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * addr -> Address to free. - * - */ -static ks_status_t free_mem(void *addr) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - void *start = NULL; - void *fence = NULL; - ks_pool_prefix_t *prefix = NULL; - ks_pool_t *pool = NULL; - - ks_assert(addr); - - start = (void *)((uintptr_t)addr - KS_POOL_PREFIX_SIZE); - prefix = (ks_pool_prefix_t *)start; - - if ((ret = check_prefix(prefix)) != KS_STATUS_SUCCESS) return ret; - - pool = prefix->pool; - - if (prefix->refs > 0) { - prefix->refs--; - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_DECREF, prefix->size, prefix->refs, addr, NULL, 0); - } - } - - if (prefix->refs > 0) { - return KS_STATUS_REFS_EXIST; - } - - fence = (void *)((uintptr_t)addr + prefix->size); - ret = check_fence(fence); - - perform_pool_cleanup_on_free(prefix); - - if (!prefix->prev && !prefix->next) pool->first = pool->last = NULL; - else if (!prefix->prev) { - pool->first = prefix->next; - pool->first->prev = NULL; - } - else if (!prefix->next) { - pool->last = prefix->prev; - pool->last->next = NULL; - } else { - prefix->prev->next = prefix->next; - prefix->next->prev = prefix->prev; - } - - pool->alloc_c--; - pool->user_alloc -= prefix->size; - - free(start); - - return ret; -} - -/***************************** exported routines *****************************/ - -/* - * ks_pool_t *ks_pool_open - * - * DESCRIPTION: - * - * Open/allocate a new memory pool. - * - * RETURNS: - * - * Success - Pool pointer which must be passed to ks_pool_close to - * deallocate. - * - * Failure - NULL - * - * ARGUMENTS: - * - * flags -> Flags to set attributes of the memory pool. See the top - * of ks_pool.h. - * - * error_p <- Pointer to ks_status_t which, if not NULL, will be set with - * a ks_pool error code. - */ -static ks_pool_t *ks_pool_raw_open(const ks_size_t flags, ks_status_t *error_p) -{ - ks_pool_t *pool = NULL; - - pool = malloc(sizeof(ks_pool_t)); - ks_assert(pool); - memset(pool, 0, sizeof(ks_pool_t)); - - pool->magic1 = KS_POOL_MAGIC; - pool->flags = flags; - pool->magic2 = KS_POOL_MAGIC; - - SET_POINTER(error_p, KS_STATUS_SUCCESS); - return pool; -} - -/* - * ks_pool_t *ks_pool_open - * - * DESCRIPTION: - * - * Open/allocate a new memory pool. - * - * RETURNS: - * - * Success - KS_SUCCESS - * - * Failure - KS_FAIL - * - * ARGUMENTS: - * - * poolP <- pointer to new pool that will be set on success - * - */ - -KS_DECLARE(ks_status_t) ks_pool_open(ks_pool_t **poolP) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_t *pool = NULL; - - ks_assert(poolP); - - pool = ks_pool_raw_open(KS_POOL_FLAG_DEFAULT, &ret); - - *poolP = pool; - - if (pool) ks_mutex_create(&pool->mutex, KS_MUTEX_FLAG_DEFAULT, NULL); - - return ret; -} - -/* - * int ks_pool_raw_close - * - * DESCRIPTION: - * - * Close/free a memory allocation pool previously opened with - * ks_pool_open. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - Ks_Pool error code - * - * ARGUMENTS: - * - * pool -> Pointer to our memory pool. - */ -static ks_status_t ks_pool_raw_close(ks_pool_t *pool) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - if ((ret = ks_pool_clear(pool)) != KS_STATUS_SUCCESS) goto done; - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_CLOSE, 0, 0, NULL, NULL, 0); - } - - ks_mutex_destroy(&pool->mutex); - - free(pool); - -done: - ks_assert(ret == KS_STATUS_SUCCESS); - return ret; -} - - -/* - * ks_status_t ks_pool_close - * - * DESCRIPTION: - * - * Close/free a memory allocation pool previously opened with - * ks_pool_open. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * poolP <-> Pointer to pointer of our memory pool. - */ - -KS_DECLARE(ks_status_t) ks_pool_close(ks_pool_t **poolP) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(poolP); - ks_assert(*poolP); - - if ((ret = ks_pool_raw_close(*poolP)) == KS_STATUS_SUCCESS) *poolP = NULL; - - return ret; -} - -/* - * int ks_pool_clear - * - * DESCRIPTION: - * - * Wipe an opened memory pool clean so we can start again. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - Ks_Pool error code - * - * ARGUMENTS: - * - * pool -> Pointer to our memory pool. - */ -KS_DECLARE(ks_status_t) ks_pool_clear(ks_pool_t *pool) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_prefix_t *prefix, *nprefix; - - ks_assert(pool); - - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) goto done; - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_CLEAR, 0, 0, NULL, NULL, 0); - } - - ks_mutex_lock(pool->mutex); - - perform_pool_cleanup(pool); - - for (prefix = pool->first; prefix; prefix = nprefix) { - nprefix = prefix->next; - // @todo check_prefix()? still want to clear out properly if some has been cleared though, not leak memory if there has been corruption - free(prefix); - } - pool->first = pool->last = NULL; - - ks_mutex_unlock(pool->mutex); - -done: - ks_assert(ret == KS_STATUS_SUCCESS); - return ret; -} - -// @todo fill in documentation -KS_DECLARE(ks_bool_t) ks_pool_verify(void *addr) -{ - if (!addr) return KS_FALSE; - if (check_prefix((ks_pool_prefix_t *)((uintptr_t)addr - KS_POOL_PREFIX_SIZE)) != KS_STATUS_SUCCESS) return KS_FALSE; - return KS_TRUE; -} - -// @todo fill in documentation -KS_DECLARE(ks_pool_t *) ks_pool_get(void *addr) -{ - ks_assert(addr); -#ifdef DEBUG - ks_pool_prefix_t *prefix = (ks_pool_prefix_t *)((uintptr_t)addr - KS_POOL_PREFIX_SIZE); - ks_status_t ret = KS_STATUS_SUCCESS; - - ret = check_prefix(prefix); - ks_assert(ret == KS_STATUS_SUCCESS); - - ret = check_pool(prefix->pool); - ks_assert(ret == KS_STATUS_SUCCESS); -#endif - return ((ks_pool_prefix_t *)((uintptr_t)addr - KS_POOL_PREFIX_SIZE))->pool; -} - -/* - * void *ks_pool_alloc_ex - * - * DESCRIPTION: - * - * Allocate space for bytes inside of an already open memory pool. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * size -> Number of bytes to allocate in the pool. Must be >0. - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ -KS_DECLARE(void *) ks_pool_alloc_ex(ks_pool_t *pool, const ks_size_t size, ks_status_t *error_p) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - void *addr = NULL; - - ks_assert(pool); - ks_assert(size); - - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) goto done; - - ks_mutex_lock(pool->mutex); - addr = alloc_mem(pool, size, &ret); - ks_mutex_unlock(pool->mutex); - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_ALLOC, size, 0, addr, NULL, 0); - } - - ks_assert(addr); - -done: - ks_assert(ret == KS_STATUS_SUCCESS); - return addr; -} - -/* - * void *ks_pool_alloc - * - * DESCRIPTION: - * - * Allocate space for bytes inside of an already open memory pool. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * - * size -> Number of bytes to allocate in the pool. Must be >0. - * - */ -KS_DECLARE(void *) ks_pool_alloc(ks_pool_t *pool, const ks_size_t size) -{ - return ks_pool_alloc_ex(pool, size, NULL); -} - - -/* - * void *ks_pool_calloc_ex - * - * DESCRIPTION: - * - * Allocate space for elements of bytes in the memory pool and zero - * the space afterwards. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. If NULL then it will do a - * normal calloc. - * - * ele_n -> Number of elements to allocate. - * - * ele_size -> Number of bytes per element being allocated. - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ -KS_DECLARE(void *) ks_pool_calloc_ex(ks_pool_t *pool, const ks_size_t ele_n, const ks_size_t ele_size, ks_status_t *error_p) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - void *addr = NULL; - ks_size_t size; - - ks_assert(pool); - ks_assert(ele_n); - ks_assert(ele_size); - - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) goto done; - - size = ele_n * ele_size; - - ks_mutex_lock(pool->mutex); - addr = alloc_mem(pool, size, &ret); - // @todo consider readding the NO_ZERO flag option, in which case must zero the user-space here based on expected calloc behaviour... memset(addr, 0, size); - ks_mutex_unlock(pool->mutex); - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_CALLOC, ele_size, ele_n, addr, NULL, 0); - } - - ks_assert(addr); - -done: - ks_assert(ret == KS_STATUS_SUCCESS); - - return addr; -} - -/* - * void *ks_pool_calloc - * - * DESCRIPTION: - * - * Allocate space for elements of bytes in the memory pool and zero - * the space afterwards. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. If NULL then it will do a - * normal calloc. - * - * ele_n -> Number of elements to allocate. - * - * ele_size -> Number of bytes per element being allocated. - * - */ -KS_DECLARE(void *) ks_pool_calloc(ks_pool_t *pool, const ks_size_t ele_n, const ks_size_t ele_size) -{ - return ks_pool_calloc_ex(pool, ele_n, ele_size, NULL); -} - -/* - * int ks_pool_free - * - * DESCRIPTION: - * - * Free an address from a memory pool. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * addr <-> Pointer to pointer of Address to free. - * - */ -KS_DECLARE(ks_status_t) ks_pool_free_ex(void **addrP) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - void *addr = NULL; - ks_pool_prefix_t *prefix = NULL; - ks_pool_t *pool = NULL; - - ks_assert(addrP); - ks_assert(*addrP); - - addr = *addrP; - - prefix = (ks_pool_prefix_t *)((uintptr_t)addr - KS_POOL_PREFIX_SIZE); - if ((ret = check_prefix(prefix)) != KS_STATUS_SUCCESS) goto done; - - pool = prefix->pool; - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) goto done; - - ks_mutex_lock(pool->mutex); - - if (pool->log_func != NULL) { - // @todo check_prefix()? - pool->log_func(pool, prefix->refs == 1 ? KS_POOL_FUNC_FREE : KS_POOL_FUNC_DECREF, prefix->size, prefix->refs - 1, addr, NULL, 0); - } - - ret = free_mem(addr); - ks_mutex_unlock(pool->mutex); - -done: - if (ret != KS_STATUS_REFS_EXIST) { - ks_assert(ret == KS_STATUS_SUCCESS); - *addrP = NULL; - } - - return ret; -} - -/* - * void *ks_pool_ref_ex - * - * DESCRIPTION: - * - * Ref count increment an address in a memoory pool. - * - * RETURNS: - * - * Success - The same pointer - * - * Failure - NULL - * - * ARGUMENTS: - * - * addr -> The addr to ref - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ -KS_DECLARE(void *) ks_pool_ref_ex(void *addr, ks_status_t *error_p) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_pool_prefix_t *prefix = NULL; - ks_pool_t *pool = NULL; - ks_size_t refs; - - ks_assert(addr); - - prefix = (ks_pool_prefix_t *)((uintptr_t)addr - KS_POOL_PREFIX_SIZE); - if ((ret = check_prefix(prefix)) != KS_STATUS_SUCCESS) goto done; - - pool = prefix->pool; - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) goto done; - - ks_mutex_lock(pool->mutex); - refs = ++prefix->refs; - ks_mutex_unlock(pool->mutex); - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_INCREF, prefix->size, refs, addr, NULL, 0); - } - -done: - ks_assert(ret == KS_STATUS_SUCCESS); - - return addr; -} - -/* - * void *ks_pool_resize_ex - * - * DESCRIPTION: - * - * Reallocate an address in a memory pool to a new size. This is - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * old_addr -> Previously allocated address. - * - * new_size -> New size of the allocation. - * - * error_p <- Pointer to integer which, if not NULL, will be set with - * a ks_pool error code. - */ -KS_DECLARE(void *) ks_pool_resize_ex(void *old_addr, const ks_size_t new_size, ks_status_t *error_p) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - ks_size_t old_size; - ks_pool_prefix_t *prefix = NULL; - ks_pool_t *pool = NULL; - void *new_addr = NULL; - ks_size_t required; - - ks_assert(old_addr); - ks_assert(new_size); - - prefix = (ks_pool_prefix_t *)((uintptr_t)old_addr - KS_POOL_PREFIX_SIZE); - if ((ret = check_prefix(prefix)) != KS_STATUS_SUCCESS) { - SET_POINTER(error_p, ret); - return NULL; - } - - pool = prefix->pool; - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) { - SET_POINTER(error_p, ret); - return NULL; - } - - ks_mutex_lock(pool->mutex); - - if (prefix->refs > 1) { - ret = KS_STATUS_NOT_ALLOWED; - goto done; - } - if (new_size == prefix->size) { - new_addr = old_addr; - goto done; - } - - old_size = prefix->size; - - required = KS_POOL_PREFIX_SIZE + new_size + KS_POOL_FENCE_SIZE; - new_addr = realloc((void *)prefix, required); - ks_assert(new_addr); - - prefix = (ks_pool_prefix_t *)new_addr; - - prefix->size = new_size; - - new_addr = (void *)((uintptr_t)new_addr + KS_POOL_PREFIX_SIZE); - write_fence((void *)((uintptr_t)new_addr + new_size)); - - if (prefix->prev) prefix->prev->next = prefix; - else pool->first = prefix; - if (prefix->next) prefix->next->prev = prefix; - else pool->last = prefix; - - if (pool->log_func != NULL) { - pool->log_func(pool, KS_POOL_FUNC_RESIZE, new_size, 0, old_addr, new_addr, old_size); - } - -done: - ks_mutex_unlock(pool->mutex); - - ks_assert(ret == KS_STATUS_SUCCESS); - - return new_addr; -} - -/* - * void *ks_pool_resize - * - * DESCRIPTION: - * - * Reallocate an address in a mmeory pool to a new size. This is - * different from realloc in that it needs the old address' size. - * - * RETURNS: - * - * Success - Pointer to the address to use. - * - * Failure - NULL - * - * ARGUMENTS: - * - * old_addr -> Previously allocated address. - * - * new_size -> New size of the allocation. - * - */ -KS_DECLARE(void *) ks_pool_resize(void *old_addr, const ks_size_t new_size) -{ - return ks_pool_resize_ex(old_addr, new_size, NULL); -} - -/* - * int ks_pool_stats - * - * DESCRIPTION: - * - * Return stats from the memory pool. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * num_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the number of pointers currently allocated in pool. - * - * user_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the number of user bytes allocated in this pool. - * - * max_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the maximum number of user bytes that have been - * allocated in this pool. - * - * tot_alloced_p <- Pointer to an unsigned long which, if not NULL, - * will be set to the total amount of space (including administrative - * overhead) used by the pool. - */ -KS_DECLARE(ks_status_t) ks_pool_stats(const ks_pool_t *pool, ks_size_t *num_alloced_p, ks_size_t *user_alloced_p, ks_size_t *max_alloced_p, ks_size_t *tot_alloced_p) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(pool); - - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) goto done; - - SET_POINTER(num_alloced_p, pool->alloc_c); - SET_POINTER(user_alloced_p, pool->user_alloc); - SET_POINTER(max_alloced_p, pool->max_alloc); - SET_POINTER(tot_alloced_p, pool->user_alloc + (pool->alloc_c * (KS_POOL_PREFIX_SIZE + KS_POOL_FENCE_SIZE))); - -done: - ks_assert(ret == KS_STATUS_SUCCESS); - return ret; -} - -/* - * int ks_pool_set_log_func - * - * DESCRIPTION: - * - * Set a logging callback function to be called whenever there was a - * memory transaction. See ks_pool_log_func_t. - * - * RETURNS: - * - * Success - KS_STATUS_SUCCESS - * - * Failure - ks_status_t error code - * - * ARGUMENTS: - * - * pool -> Pointer to the memory pool. - * - * log_func -> Log function (defined in ks_pool.h) which will be called - * with each ks_pool transaction. - */ -KS_DECLARE(ks_status_t) ks_pool_set_log_func(ks_pool_t *pool, ks_pool_log_func_t log_func) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(pool); - ks_assert(log_func); - - if ((ret = check_pool(pool)) != KS_STATUS_SUCCESS) goto done; - - pool->log_func = log_func; - -done: - ks_assert(ret == KS_STATUS_SUCCESS); - return ret; -} - -/* - * const char *ks_pool_strerror - * - * DESCRIPTION: - * - * Return the corresponding string for the error number. - * - * RETURNS: - * - * Success - String equivalient of the error. - * - * Failure - String "invalid error code" - * - * ARGUMENTS: - * - * error -> ks_status_t that we are converting. - */ -KS_DECLARE(const char *) ks_pool_strerror(const ks_status_t error) -{ - switch (error) { - case KS_STATUS_SUCCESS: - return "no error"; - break; - case KS_STATUS_ARG_NULL: - return "function argument is null"; - break; - case KS_STATUS_ARG_INVALID: - return "function argument is invalid"; - break; - case KS_STATUS_PNT: - return "invalid ks_pool pointer"; - break; - case KS_STATUS_POOL_OVER: - return "ks_pool structure was overwritten"; - break; - case KS_STATUS_PAGE_SIZE: - return "could not get system page-size"; - break; - case KS_STATUS_OPEN_ZERO: - return "could not open /dev/zero"; - break; - case KS_STATUS_NO_MEM: - return "no memory available"; - break; - case KS_STATUS_SIZE: - return "error processing requested size"; - break; - case KS_STATUS_TOO_BIG: - return "allocation exceeds pool max size"; - break; - case KS_STATUS_MEM: - return "invalid memory address"; - break; - case KS_STATUS_MEM_OVER: - return "memory lower bounds overwritten"; - break; - case KS_STATUS_NOT_FOUND: - return "memory block not found in pool"; - break; - case KS_STATUS_IS_FREE: - return "memory address has already been freed"; - break; - case KS_STATUS_BLOCK_STAT: - return "invalid internal block status"; - break; - case KS_STATUS_FREE_ADDR: - return "invalid internal free address"; - break; - case KS_STATUS_NO_PAGES: - return "no available pages left in pool"; - break; - case KS_STATUS_ALLOC: - return "system alloc function failed"; - break; - case KS_STATUS_PNT_OVER: - return "user pointer admin space overwritten"; - break; - case KS_STATUS_INVALID_POINTER: - return "pointer is not valid"; - break; - default: - break; - } - - return "invalid error code"; -} - -KS_DECLARE(char *) ks_pstrdup(ks_pool_t *pool, const char *str) -{ - char *result; - ks_size_t len; - - if (!str) { - return NULL; - } - - len = (ks_size_t)strlen(str) + 1; - result = ks_pool_alloc(pool, len); - memcpy(result, str, len); - - return result; -} - -KS_DECLARE(char *) ks_pstrndup(ks_pool_t *pool, const char *str, ks_size_t len) -{ - char *result; - const char *end; - - if (!str) { - return NULL; - } - - end = memchr(str, '\0', len); - - if (!end) { - len = end - str; - } - - result = ks_pool_alloc(pool, len + 1); - memcpy(result, str, len); - result[len] = '\0'; - - return result; -} - -KS_DECLARE(char *) ks_pstrmemdup(ks_pool_t *pool, const char *str, ks_size_t len) -{ - char *result; - - if (!str) { - return NULL; - } - - result = ks_pool_alloc(pool, len + 1); - memcpy(result, str, len); - result[len] = '\0'; - - return result; -} - -KS_DECLARE(void *) ks_pmemdup(ks_pool_t *pool, const void *buf, ks_size_t len) -{ - void *result; - - if (!buf) { - return NULL; - } - - result = ks_pool_alloc(pool, len); - memcpy(result, buf, len); - - return result; -} - -KS_DECLARE(char *) ks_pstrcat(ks_pool_t *pool, ...) -{ - char *endp, *argp; - char *result; - ks_size_t lengths[10]; - int i = 0; - ks_size_t len = 0; - va_list ap; - - va_start(ap, pool); - - /* get lengths so we know what to allocate, cache some so we don't have to double strlen those */ - - while ((argp = va_arg(ap, char *))) { - ks_size_t arglen = strlen(argp); - if (i < 10) lengths[i++] = arglen; - len += arglen; - } - - va_end(ap); - - result = (char *) ks_pool_alloc(pool, len + 1); - endp = result; - - va_start(ap, pool); - - i = 0; - - while ((argp = va_arg(ap, char *))) { - len = (i < 10) ? lengths[i++] : strlen(argp); - memcpy(endp, argp, len); - endp += len; - } - - va_end(ap); - - *endp = '\0'; - - return result; -} - -KS_DECLARE(char *) ks_psprintf(ks_pool_t *pool, const char *fmt, ...) -{ - va_list ap; - char *result; - va_start(ap, fmt); - result = ks_vpprintf(pool, fmt, ap); - va_end(ap); - - return result; -} - - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_printf.c b/libs/libks/src/ks_printf.c deleted file mode 100644 index ea5e09fc1d..0000000000 --- a/libs/libks/src/ks_printf.c +++ /dev/null @@ -1,974 +0,0 @@ -/* -** The "printf" code that follows dates from the 1980's. It is in -** the public domain. The original comments are included here for -** completeness. They are very out-of-date but might be useful as -** an historical reference. Most of the "enhancements" have been backed -** out so that the functionality is now the same as standard printf(). -** -************************************************************************** -** -** The following modules is an enhanced replacement for the "printf" subroutines -** found in the standard C library. The following enhancements are -** supported: -** -** + Additional functions. The standard set of "printf" functions -** includes printf, fprintf, sprintf, vprintf, vfprintf, and -** vsprintf. This module adds the following: -** -** * snprintf -- Works like sprintf, but has an extra argument -** which is the size of the buffer written to. -** -** * mprintf -- Similar to sprintf. Writes output to memory -** obtained from malloc. -** -** * xprintf -- Calls a function to dispose of output. -** -** * nprintf -- No output, but returns the number of characters -** that would have been output by printf. -** -** * A v- version (ex: vsnprintf) of every function is also -** supplied. -** -** + A few extensions to the formatting notation are supported: -** -** * The "=" flag (similar to "-") causes the output to be -** be centered in the appropriately sized field. -** -** * The %b field outputs an integer in binary notation. -** -** * The %c field now accepts a precision. The character output -** is repeated by the number of times the precision specifies. -** -** * The %' field works like %c, but takes as its character the -** next character of the format string, instead of the next -** argument. For example, printf("%.78'-") prints 78 minus -** signs, the same as printf("%.78c",'-'). -** -** + When compiled using GCC on a SPARC, this version of printf is -** faster than the library printf for SUN OS 4.1. -** -** + All functions are fully reentrant. -** -*/ -/* - * 20090210 (stkn): - * Taken from sqlite-3.3.x, - * renamed SQLITE_ -> KS_, - * renamed visible functions to ks_* - * disabled functions without extra conversion specifiers - */ - -#include - -#define LONGDOUBLE_TYPE long double - -/* -** Conversion types fall into various categories as defined by the -** following enumeration. -*/ -#define etRADIX 1 /* Integer types. %d, %x, %o, and so forth */ -#define etFLOAT 2 /* Floating point. %f */ -#define etEXP 3 /* Exponentional notation. %e and %E */ -#define etGENERIC 4 /* Floating or exponential, depending on exponent. %g */ -#define etSIZE 5 /* Return number of characters processed so far. %n */ -#define etSTRING 6 /* Strings. %s */ -#define etDYNSTRING 7 /* Dynamically allocated strings. %z */ -#define etPERCENT 8 /* Percent symbol. %% */ -#define etCHARX 9 /* Characters. %c */ -/* The rest are extensions, not normally found in printf() */ -#define etCHARLIT 10 /* Literal characters. %' */ -#define etSQLESCAPE 11 /* Strings with '\'' doubled. %q */ -#define etSQLESCAPE2 12 /* Strings with '\'' doubled and enclosed in '', - NULL pointers replaced by SQL NULL. %Q */ -#ifdef __UNSUPPORTED__ -#define etTOKEN 13 /* a pointer to a Token structure */ -#define etSRCLIST 14 /* a pointer to a SrcList */ -#endif -#define etPOINTER 15 /* The %p conversion */ -#define etSQLESCAPE3 16 -#define etSQLESCAPE4 17 - -/* -** An "etByte" is an 8-bit unsigned value. -*/ -typedef unsigned char etByte; - -/* -** Each builtin conversion character (ex: the 'd' in "%d") is described -** by an instance of the following structure -*/ -typedef struct et_info { /* Information about each format field */ - char fmttype; /* The format field code letter */ - etByte base; /* The base for radix conversion */ - etByte flags; /* One or more of FLAG_ constants below */ - etByte type; /* Conversion paradigm */ - etByte charset; /* Offset into aDigits[] of the digits string */ - etByte prefix; /* Offset into aPrefix[] of the prefix string */ -} et_info; - -/* -** Allowed values for et_info.flags -*/ -#define FLAG_SIGNED 1 /* True if the value to convert is signed */ -#define FLAG_INTERN 2 /* True if for internal use only */ -#define FLAG_STRING 4 /* Allow infinity precision */ - - -/* -** The following table is searched linearly, so it is good to put the -** most frequently used conversion types first. -*/ -static const char aDigits[] = "0123456789ABCDEF0123456789abcdef"; -static const char aPrefix[] = "-x0\000X0"; -static const et_info fmtinfo[] = { - {'d', 10, 1, etRADIX, 0, 0}, - {'s', 0, 4, etSTRING, 0, 0}, - {'g', 0, 1, etGENERIC, 30, 0}, - {'z', 0, 6, etDYNSTRING, 0, 0}, - {'q', 0, 4, etSQLESCAPE, 0, 0}, - {'Q', 0, 4, etSQLESCAPE2, 0, 0}, - {'w', 0, 4, etSQLESCAPE3, 0, 0}, - {'y', 0, 4, etSQLESCAPE4, 0, 0}, - {'c', 0, 0, etCHARX, 0, 0}, - {'o', 8, 0, etRADIX, 0, 2}, - {'u', 10, 0, etRADIX, 0, 0}, - {'x', 16, 0, etRADIX, 16, 1}, - {'X', 16, 0, etRADIX, 0, 4}, -#ifndef KS_OMIT_FLOATING_POINT - {'f', 0, 1, etFLOAT, 0, 0}, - {'e', 0, 1, etEXP, 30, 0}, - {'E', 0, 1, etEXP, 14, 0}, - {'G', 0, 1, etGENERIC, 14, 0}, -#endif - {'i', 10, 1, etRADIX, 0, 0}, - {'n', 0, 0, etSIZE, 0, 0}, - {'%', 0, 0, etPERCENT, 0, 0}, - {'p', 16, 0, etPOINTER, 0, 1}, -#ifdef __UNSUPPORTED__ - {'T', 0, 2, etTOKEN, 0, 0}, - {'S', 0, 2, etSRCLIST, 0, 0}, -#endif -}; - -#define etNINFO (sizeof(fmtinfo)/sizeof(fmtinfo[0])) - -/* -** If KS_OMIT_FLOATING_POINT is defined, then none of the floating point -** conversions will work. -*/ -#ifndef KS_OMIT_FLOATING_POINT -/* -** "*val" is a double such that 0.1 <= *val < 10.0 -** Return the ascii code for the leading digit of *val, then -** multiply "*val" by 10.0 to renormalize. -** -** Example: -** input: *val = 3.14159 -** output: *val = 1.4159 function return = '3' -** -** The counter *cnt is incremented each time. After counter exceeds -** 16 (the number of significant digits in a 64-bit float) '0' is -** always returned. -*/ -static int et_getdigit(LONGDOUBLE_TYPE * val, int *cnt) -{ - int digit; - LONGDOUBLE_TYPE d; - if ((*cnt)++ >= 16) - return '0'; - digit = (int) *val; - d = digit; - digit += '0'; - *val = (*val - d) * 10.0; - return digit; -} -#endif /* KS_OMIT_FLOATING_POINT */ - -/* -** The root program. All variations call this core. -** -** INPUTS: -** func This is a pointer to a function taking three arguments -** 1. A pointer to anything. Same as the "arg" parameter. -** 2. A pointer to the list of characters to be output -** (Note, this list is NOT null terminated.) -** 3. An integer number of characters to be output. -** (Note: This number might be zero.) -** -** arg This is the pointer to anything which will be passed as the -** first argument to "func". Use it for whatever you like. -** -** fmt This is the format string, as in the usual print. -** -** ap This is a pointer to a list of arguments. Same as in -** vfprint. -** -** OUTPUTS: -** The return value is the total number of characters sent to -** the function "func". Returns -1 on a error. -** -** Note that the order in which automatic variables are declared below -** seems to make a big difference in determining how fast this beast -** will run. -*/ -static int vxprintf(void (*func) (void *, const char *, int), /* Consumer of text */ - void *arg, /* First argument to the consumer */ - int useExtended, /* Allow extended %-conversions */ - const char *fmt, /* Format string */ - va_list ap /* arguments */ - ) -{ - int c; /* Next character in the format string */ - char *bufpt; /* Pointer to the conversion buffer */ - int precision; /* Precision of the current field */ - int length; /* Length of the field */ - int idx; /* A general purpose loop counter */ - int count; /* Total number of characters output */ - int width; /* Width of the current field */ - etByte flag_leftjustify; /* True if "-" flag is present */ - etByte flag_plussign; /* True if "+" flag is present */ - etByte flag_blanksign; /* True if " " flag is present */ - etByte flag_alternateform; /* True if "#" flag is present */ - etByte flag_altform2; /* True if "!" flag is present */ - etByte flag_zeropad; /* True if field width constant starts with zero */ - etByte flag_long; /* True if "l" flag is present */ - etByte flag_longlong; /* True if the "ll" flag is present */ - etByte done; /* Loop termination flag */ - uint64_t longvalue; /* Value for integer types */ - LONGDOUBLE_TYPE realvalue; /* Value for real types */ - const et_info *infop; /* Pointer to the appropriate info structure */ - char buf[etBUFSIZE]; /* Conversion buffer */ - char prefix; /* Prefix character. "+" or "-" or " " or '\0'. */ - etByte errorflag = 0; /* True if an error is encountered */ - etByte xtype = 0; /* Conversion paradigm */ - char *zExtra; /* Extra memory used for etTCLESCAPE conversions */ - static const char spaces[] = " "; -#define etSPACESIZE (sizeof(spaces)-1) -#ifndef KS_OMIT_FLOATING_POINT - int exp, e2; /* exponent of real numbers */ - double rounder; /* Used for rounding floating point values */ - etByte flag_dp; /* True if decimal point should be shown */ - etByte flag_rtz; /* True if trailing zeros should be removed */ - etByte flag_exp; /* True to force display of the exponent */ - int nsd; /* Number of significant digits returned */ -#endif - - func(arg, "", 0); - count = length = 0; - bufpt = 0; - for (; (c = (*fmt)) != 0; ++fmt) { - if (c != '%') { - int amt; - bufpt = (char *) fmt; - amt = 1; - while ((c = (*++fmt)) != '%' && c != 0) - amt++; - (*func) (arg, bufpt, amt); - count += amt; - if (c == 0) - break; - } - if ((c = (*++fmt)) == 0) { - errorflag = 1; - (*func) (arg, "%", 1); - count++; - break; - } - /* Find out what flags are present */ - flag_leftjustify = flag_plussign = flag_blanksign = flag_alternateform = flag_altform2 = flag_zeropad = 0; - done = 0; - do { - switch (c) { - case '-': - flag_leftjustify = 1; - break; - case '+': - flag_plussign = 1; - break; - case ' ': - flag_blanksign = 1; - break; - case '#': - flag_alternateform = 1; - break; - case '!': - flag_altform2 = 1; - break; - case '0': - flag_zeropad = 1; - break; - default: - done = 1; - break; - } - } while (!done && (c = (*++fmt)) != 0); - /* Get the field width */ - width = 0; - if (c == '*') { - width = va_arg(ap, int); - if (width < 0) { - flag_leftjustify = 1; - width = -width; - } - c = *++fmt; - } else { - while (c >= '0' && c <= '9') { - width = width * 10 + c - '0'; - c = *++fmt; - } - } - if (width > etBUFSIZE - 10) { - width = etBUFSIZE - 10; - } - /* Get the precision */ - if (c == '.') { - precision = 0; - c = *++fmt; - if (c == '*') { - precision = va_arg(ap, int); - if (precision < 0) - precision = -precision; - c = *++fmt; - } else { - while (c >= '0' && c <= '9') { - precision = precision * 10 + c - '0'; - c = *++fmt; - } - } - } else { - precision = -1; - } - /* Get the conversion type modifier */ - if (c == 'l') { - flag_long = 1; - c = *++fmt; - if (c == 'l') { - flag_longlong = 1; - c = *++fmt; - } else { - flag_longlong = 0; - } - } else { - flag_long = flag_longlong = 0; - } - /* Fetch the info entry for the field */ - infop = 0; - for (idx = 0; idx < etNINFO; idx++) { - if (c == fmtinfo[idx].fmttype) { - infop = &fmtinfo[idx]; - if (useExtended || (infop->flags & FLAG_INTERN) == 0) { - xtype = infop->type; - } else { - return -1; - } - break; - } - } - zExtra = 0; - if (infop == 0) { - return -1; - } - - - /* Limit the precision to prevent overflowing buf[] during conversion */ - if (precision > etBUFSIZE - 40 && (infop->flags & FLAG_STRING) == 0) { - precision = etBUFSIZE - 40; - } - - /* - ** At this point, variables are initialized as follows: - ** - ** flag_alternateform TRUE if a '#' is present. - ** flag_altform2 TRUE if a '!' is present. - ** flag_plussign TRUE if a '+' is present. - ** flag_leftjustify TRUE if a '-' is present or if the - ** field width was negative. - ** flag_zeropad TRUE if the width began with 0. - ** flag_long TRUE if the letter 'l' (ell) prefixed - ** the conversion character. - ** flag_longlong TRUE if the letter 'll' (ell ell) prefixed - ** the conversion character. - ** flag_blanksign TRUE if a ' ' is present. - ** width The specified field width. This is - ** always non-negative. Zero is the default. - ** precision The specified precision. The default - ** is -1. - ** xtype The class of the conversion. - ** infop Pointer to the appropriate info struct. - */ - switch (xtype) { - case etPOINTER: - flag_longlong = sizeof(char *) == sizeof(int64_t); - flag_long = sizeof(char *) == sizeof(long int); - /* Fall through into the next case */ - case etRADIX: - if (infop->flags & FLAG_SIGNED) { - int64_t v; - if (flag_longlong) - v = va_arg(ap, int64_t); - else if (flag_long) - v = va_arg(ap, long int); - else - v = va_arg(ap, int); - if (v < 0) { - longvalue = -v; - prefix = '-'; - } else { - longvalue = v; - if (flag_plussign) - prefix = '+'; - else if (flag_blanksign) - prefix = ' '; - else - prefix = 0; - } - } else { - if (flag_longlong) - longvalue = va_arg(ap, uint64_t); - else if (flag_long) - longvalue = va_arg(ap, unsigned long int); - else - longvalue = va_arg(ap, unsigned int); - prefix = 0; - } - if (longvalue == 0) - flag_alternateform = 0; - if (flag_zeropad && precision < width - (prefix != 0)) { - precision = width - (prefix != 0); - } - bufpt = &buf[etBUFSIZE - 1]; - { - register const char *cset; /* Use registers for speed */ - register int base; - cset = &aDigits[infop->charset]; - base = infop->base; - do { /* Convert to ascii */ - *(--bufpt) = cset[longvalue % base]; - longvalue = longvalue / base; - } while (longvalue > 0); - } - length = (int)(&buf[etBUFSIZE - 1] - bufpt); - for (idx = precision - length; idx > 0; idx--) { - *(--bufpt) = '0'; /* Zero pad */ - } - if (prefix) - *(--bufpt) = prefix; /* Add sign */ - if (flag_alternateform && infop->prefix) { /* Add "0" or "0x" */ - const char *pre; - char x; - pre = &aPrefix[infop->prefix]; - if (*bufpt != pre[0]) { - for (; (x = (*pre)) != 0; pre++) - *(--bufpt) = x; - } - } - length = (int)(&buf[etBUFSIZE - 1] - bufpt); - break; - case etFLOAT: - case etEXP: - case etGENERIC: - realvalue = va_arg(ap, double); -#ifndef KS_OMIT_FLOATING_POINT - if (precision < 0) - precision = 6; /* Set default precision */ - if (precision > etBUFSIZE / 2 - 10) - precision = etBUFSIZE / 2 - 10; - if (realvalue < 0.0) { - realvalue = -realvalue; - prefix = '-'; - } else { - if (flag_plussign) - prefix = '+'; - else if (flag_blanksign) - prefix = ' '; - else - prefix = 0; - } - if (xtype == etGENERIC && precision > 0) - precision--; -#if 0 - /* Rounding works like BSD when the constant 0.4999 is used. Wierd! */ - for (idx = precision, rounder = 0.4999; idx > 0; idx--, rounder *= 0.1); -#else - /* It makes more sense to use 0.5 */ - for (idx = precision, rounder = 0.5; idx > 0; idx--, rounder *= 0.1) { - } -#endif - if (xtype == etFLOAT) - realvalue += rounder; - /* Normalize realvalue to within 10.0 > realvalue >= 1.0 */ - exp = 0; - if (realvalue > 0.0) { - while (realvalue >= 1e32 && exp <= 350) { - realvalue *= 1e-32; - exp += 32; - } - while (realvalue >= 1e8 && exp <= 350) { - realvalue *= 1e-8; - exp += 8; - } - while (realvalue >= 10.0 && exp <= 350) { - realvalue *= 0.1; - exp++; - } - while (realvalue < 1e-8 && exp >= -350) { - realvalue *= 1e8; - exp -= 8; - } - while (realvalue < 1.0 && exp >= -350) { - realvalue *= 10.0; - exp--; - } - if (exp > 350 || exp < -350) { - bufpt = "NaN"; - length = 3; - break; - } - } - bufpt = buf; - /* - ** If the field type is etGENERIC, then convert to either etEXP - ** or etFLOAT, as appropriate. - */ - flag_exp = xtype == etEXP; - if (xtype != etFLOAT) { - realvalue += rounder; - if (realvalue >= 10.0) { - realvalue *= 0.1; - exp++; - } - } - if (xtype == etGENERIC) { - flag_rtz = !flag_alternateform; - if (exp < -4 || exp > precision) { - xtype = etEXP; - } else { - precision = precision - exp; - xtype = etFLOAT; - } - } else { - flag_rtz = 0; - } - if (xtype == etEXP) { - e2 = 0; - } else { - e2 = exp; - } - nsd = 0; - flag_dp = (precision > 0) | flag_alternateform | flag_altform2; - /* The sign in front of the number */ - if (prefix) { - *(bufpt++) = prefix; - } - /* Digits prior to the decimal point */ - if (e2 < 0) { - *(bufpt++) = '0'; - } else { - for (; e2 >= 0; e2--) { - *(bufpt++) = (char) et_getdigit(&realvalue, &nsd); - } - } - /* The decimal point */ - if (flag_dp) { - *(bufpt++) = '.'; - } - /* "0" digits after the decimal point but before the first - ** significant digit of the number */ - for (e2++; e2 < 0 && precision > 0; precision--, e2++) { - *(bufpt++) = '0'; - } - /* Significant digits after the decimal point */ - while ((precision--) > 0) { - *(bufpt++) = (char) et_getdigit(&realvalue, &nsd); - } - /* Remove trailing zeros and the "." if no digits follow the "." */ - if (flag_rtz && flag_dp) { - while (bufpt[-1] == '0') - *(--bufpt) = 0; - assert(bufpt > buf); - if (bufpt[-1] == '.') { - if (flag_altform2) { - *(bufpt++) = '0'; - } else { - *(--bufpt) = 0; - } - } - } - /* Add the "eNNN" suffix */ - if (flag_exp || (xtype == etEXP && exp)) { - *(bufpt++) = aDigits[infop->charset]; - if (exp < 0) { - *(bufpt++) = '-'; - exp = -exp; - } else { - *(bufpt++) = '+'; - } - if (exp >= 100) { - *(bufpt++) = (char) (exp / 100) + '0'; /* 100's digit */ - exp %= 100; - } - *(bufpt++) = (char) exp / 10 + '0'; /* 10's digit */ - *(bufpt++) = exp % 10 + '0'; /* 1's digit */ - } - *bufpt = 0; - - /* The converted number is in buf[] and zero terminated. Output it. - ** Note that the number is in the usual order, not reversed as with - ** integer conversions. */ - length = (int)(bufpt - buf); - bufpt = buf; - - /* Special case: Add leading zeros if the flag_zeropad flag is - ** set and we are not left justified */ - if (flag_zeropad && !flag_leftjustify && length < width) { - int i; - int nPad = width - length; - for (i = width; i >= nPad; i--) { - bufpt[i] = bufpt[i - nPad]; - } - i = prefix != 0; - while (nPad--) - bufpt[i++] = '0'; - length = width; - } -#endif - break; - case etSIZE: - *(va_arg(ap, int *)) = count; - length = width = 0; - break; - case etPERCENT: - buf[0] = '%'; - bufpt = buf; - length = 1; - break; - case etCHARLIT: - case etCHARX: - c = buf[0] = (char) (xtype == etCHARX ? va_arg(ap, int) : *++fmt); - if (precision >= 0) { - for (idx = 1; idx < precision; idx++) - buf[idx] = (char) c; - length = precision; - } else { - length = 1; - } - bufpt = buf; - break; - case etSTRING: - case etDYNSTRING: - bufpt = va_arg(ap, char *); - if (bufpt == 0) { - bufpt = ""; - } else if (xtype == etDYNSTRING) { - zExtra = bufpt; - } - length = (int)strlen(bufpt); - if (precision >= 0 && precision < length) - length = precision; - break; - case etSQLESCAPE: - case etSQLESCAPE2: - case etSQLESCAPE4: - case etSQLESCAPE3:{ - int i, j, n, ch, isnull; - int needQuote; - char *escarg = va_arg(ap, char *); - isnull = escarg == 0; - if (isnull) - escarg = (xtype == etSQLESCAPE2 ? "NULL" : "(NULL)"); - for (i = n = 0; (ch = escarg[i]) != 0; i++) { - if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\')) - n++; - } - needQuote = !isnull && xtype == etSQLESCAPE2; - n += i + 1 + needQuote * 2; - if (n > etBUFSIZE) { - bufpt = zExtra = malloc(n); - if (bufpt == 0) - return -1; - } else { - bufpt = buf; - } - j = 0; - if (needQuote) - bufpt[j++] = '\''; - for (i = 0; (ch = escarg[i]) != 0; i++) { - bufpt[j++] = (char) ch; - if (xtype == etSQLESCAPE4) { - if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\')) { - bufpt[j] = (char) ch; - bufpt[j-1] = (char) '\\'; - j++; - } - } else { - if (ch == '\'' || (xtype == etSQLESCAPE3 && ch == '\\')) - bufpt[j++] = (char) ch; - } - } - if (needQuote) - bufpt[j++] = '\''; - bufpt[j] = 0; - length = j; - /* The precision is ignored on %q and %Q */ - /* if ( precision>=0 && precisionz) { - (*func) (arg, (char *) pToken->z, pToken->n); - } - length = width = 0; - break; - } - case etSRCLIST:{ - SrcList *pSrc = va_arg(ap, SrcList *); - int k = va_arg(ap, int); - struct SrcList_item *pItem = &pSrc->a[k]; - assert(k >= 0 && k < pSrc->nSrc); - if (pItem->zDatabase && pItem->zDatabase[0]) { - (*func) (arg, pItem->zDatabase, strlen(pItem->zDatabase)); - (*func) (arg, ".", 1); - } - (*func) (arg, pItem->zName, strlen(pItem->zName)); - length = width = 0; - break; - } -#endif - } /* End switch over the format type */ - /* - ** The text of the conversion is pointed to by "bufpt" and is - ** "length" characters long. The field width is "width". Do - ** the output. - */ - if (!flag_leftjustify) { - register int nspace; - nspace = width - length; - if (nspace > 0) { - count += nspace; - while (nspace >= etSPACESIZE) { - (*func) (arg, spaces, etSPACESIZE); - nspace -= etSPACESIZE; - } - if (nspace > 0) - (*func) (arg, spaces, nspace); - } - } - if (length > 0) { - (*func) (arg, bufpt, length); - count += length; - } - if (flag_leftjustify) { - register int nspace; - nspace = width - length; - if (nspace > 0) { - count += nspace; - while (nspace >= etSPACESIZE) { - (*func) (arg, spaces, etSPACESIZE); - nspace -= etSPACESIZE; - } - if (nspace > 0) - (*func) (arg, spaces, nspace); - } - } - if (zExtra) { - free(zExtra); - } - } /* End for loop over the format string */ - return errorflag ? -1 : count; -} /* End of function */ - - -/* This structure is used to store state information about the -** write to memory that is currently in progress. -*/ -struct sgMprintf { - char *zBase; /* A base allocation */ - char *zText; /* The string collected so far */ - int nChar; /* Length of the string so far */ - int nTotal; /* Output size if unconstrained */ - int nAlloc; /* Amount of space allocated in zText */ - void *arg; /* Third arg to the realloc callback */ - void *(*xRealloc) (void *, int, void *); /* Function used to realloc memory */ -}; - -/* -** This function implements the callback from vxprintf. -** -** This routine add nNewChar characters of text in zNewText to -** the sgMprintf structure pointed to by "arg". -*/ -static void mout(void *arg, const char *zNewText, int nNewChar) -{ - struct sgMprintf *pM = (struct sgMprintf *) arg; - pM->nTotal += nNewChar; - if (pM->nChar + nNewChar + 1 > pM->nAlloc) { - if (pM->xRealloc == 0) { - nNewChar = pM->nAlloc - pM->nChar - 1; - } else { - pM->nAlloc = pM->nChar + nNewChar * 2 + 1; - if (pM->zText == pM->zBase) { - pM->zText = pM->xRealloc(0, pM->nAlloc, pM->arg); - if (pM->zText && pM->nChar) { - memcpy(pM->zText, pM->zBase, pM->nChar); - } - } else { - char *zNew; - zNew = pM->xRealloc(pM->zText, pM->nAlloc, pM->arg); - if (zNew) { - pM->zText = zNew; - } - } - } - } - if (pM->zText) { - if (nNewChar > 0) { - memcpy(&pM->zText[pM->nChar], zNewText, nNewChar); - pM->nChar += nNewChar; - } - pM->zText[pM->nChar] = 0; - } -} - -/* -** This routine is a wrapper around xprintf() that invokes mout() as -** the consumer. -*/ -static char *base_vprintf(void *(*xRealloc) (void *, int, void *), /* Routine to realloc memory. May be NULL */ - int useInternal, /* Use internal %-conversions if true */ - char *zInitBuf, /* Initially write here, before mallocing */ - int nInitBuf, /* Size of zInitBuf[] */ - const char *zFormat, /* format string */ - va_list ap, /* arguments */ - void *realloc_arg /*arg to pass to realloc function*/ - ) -{ - struct sgMprintf sM; - sM.zBase = sM.zText = zInitBuf; - sM.nChar = sM.nTotal = 0; - sM.nAlloc = nInitBuf; - sM.xRealloc = xRealloc; - sM.arg = realloc_arg; - vxprintf(mout, &sM, useInternal, zFormat, ap); - if (xRealloc) { - if (sM.zText == sM.zBase) { - sM.zText = xRealloc(0, sM.nChar + 1, realloc_arg); - if (sM.zText) { - memcpy(sM.zText, sM.zBase, sM.nChar + 1); - } - } else if (sM.nAlloc > sM.nChar + 10) { - char *zNew = xRealloc(sM.zText, sM.nChar + 1, realloc_arg); - if (zNew) { - sM.zText = zNew; - } - } - } - return sM.zText; -} - -/* -** Realloc that is a real function, not a macro. -*/ -static void *printf_realloc(void *old, int size, void *arg) -{ - return realloc(old, size); -} - -/* -** Print into memory. Omit the internal %-conversion extensions. -*/ -KS_DECLARE(char *) ks_vmprintf(const char *zFormat, va_list ap) -{ - char zBase[KS_PRINT_BUF_SIZE]; - return base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap, NULL); -} - -/* -** Print into memory. Omit the internal %-conversion extensions. -*/ -KS_DECLARE(char *) ks_mprintf(const char *zFormat, ...) -{ - va_list ap; - char *z; - char zBase[KS_PRINT_BUF_SIZE]; - va_start(ap, zFormat); - z = base_vprintf(printf_realloc, 0, zBase, sizeof(zBase), zFormat, ap, NULL); - va_end(ap); - return z; -} - -/* -** pool_realloc function -*/ -static void *pool_realloc(void *old, int size, void *arg) -{ - void *addr = NULL; - ks_pool_t *pool = (ks_pool_t *)arg; - if (!old || !ks_pool_verify(old)) addr = ks_pool_alloc(pool, size); - else addr = ks_pool_resize(old, size); - return addr; -} - -/* -** Print into pool memory. Omit the internal %-conversion extensions. -*/ -KS_DECLARE(char *) ks_vpprintf(ks_pool_t *pool, const char *zFormat, va_list ap) -{ - char zBase[KS_PRINT_BUF_SIZE]; - return base_vprintf(pool_realloc, 0, zBase, sizeof(zBase), zFormat, ap, pool); -} - -/* -** Print into pool memory. Omit the internal %-conversion extensions. -*/ -KS_DECLARE(char *) ks_pprintf(ks_pool_t *pool, const char *zFormat, ...) -{ - va_list ap; - char *z; - char zBase[KS_PRINT_BUF_SIZE]; - va_start(ap, zFormat); - z = base_vprintf(pool_realloc, 0, zBase, sizeof(zBase), zFormat, ap, pool); - va_end(ap); - return z; -} - -/* -** ks_vsnprintf() works like vsnprintf() except that it ignores the -** current locale settings. This is important for SQLite because we -** are not able to use a "," as the decimal point in place of "." as -** specified by some locales. -*/ -KS_DECLARE(char *) ks_vsnprintfv(char *zBuf, int n, const char *zFormat, va_list ap) -{ - return base_vprintf(0, 0, zBuf, n, zFormat, ap, NULL); -} - -/* -** ks_snprintf() works like snprintf() except that it ignores the -** current locale settings. This is important for SQLite because we -** are not able to use a "," as the decimal point in place of "." as -** specified by some locales. -*/ - -KS_DECLARE(char *) ks_snprintfv(char *zBuf, int n, const char *zFormat, ...) -{ - char *z; - va_list ap; - - va_start(ap, zFormat); - z = base_vprintf(0, 0, zBuf, n, zFormat, ap, NULL); - va_end(ap); - return z; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_q.c b/libs/libks/src/ks_q.c deleted file mode 100644 index 364aa68187..0000000000 --- a/libs/libks/src/ks_q.c +++ /dev/null @@ -1,471 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - -typedef struct ks_qnode_s { - void *ptr; - struct ks_qnode_s *next; - struct ks_qnode_s *prev; -} ks_qnode_t; - -struct ks_q_s { - ks_flush_fn_t flush_fn; - void *flush_data; - ks_size_t len; - ks_size_t maxlen; - ks_cond_t *pop_cond; - ks_cond_t *push_cond; - ks_mutex_t *list_mutex; - uint32_t pushers; - uint32_t poppers; - struct ks_qnode_s *head; - struct ks_qnode_s *tail; - struct ks_qnode_s *empty; - uint8_t active; -}; - -static void ks_q_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - ks_q_t *q = (ks_q_t *) ptr; - ks_qnode_t *np, *fp; - - if (type == KS_MPCL_GLOBAL_FREE) { - return; - } - - switch(action) { - case KS_MPCL_ANNOUNCE: - if (q->active) { - ks_q_flush(q); - ks_q_term(q); - } - break; - case KS_MPCL_TEARDOWN: - np = q->head; - while(np) { - fp = np; - np = np->next; - ks_pool_free(&fp); - } - - np = q->empty; - while(np) { - fp = np; - np = np->next; - ks_pool_free(&fp); - } - break; - case KS_MPCL_DESTROY: - ks_cond_destroy(&q->pop_cond); - ks_cond_destroy(&q->push_cond); - ks_mutex_destroy(&q->list_mutex); - break; - } -} - -KS_DECLARE(ks_status_t) ks_q_flush(ks_q_t *q) -{ - void *ptr; - - if (!q->active) return KS_STATUS_INACTIVE; - if (!q->flush_fn) return KS_STATUS_FAIL; - - while(ks_q_trypop(q, &ptr) == KS_STATUS_SUCCESS) { - q->flush_fn(q, ptr, q->flush_data); - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_q_set_flush_fn(ks_q_t *q, ks_flush_fn_t fn, void *flush_data) -{ - if (!q->active) return KS_STATUS_INACTIVE; - - q->flush_fn = fn; - q->flush_data = flush_data; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_q_wake(ks_q_t *q) -{ - ks_mutex_lock(q->list_mutex); - ks_cond_broadcast(q->push_cond); - ks_cond_broadcast(q->pop_cond); - ks_mutex_unlock(q->list_mutex); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_size_t) ks_q_term(ks_q_t *q) -{ - int active; - - ks_mutex_lock(q->list_mutex); - active = q->active; - q->active = 0; - ks_mutex_unlock(q->list_mutex); - - if (active) { - ks_q_wake(q); - } - - return active ? KS_STATUS_SUCCESS : KS_STATUS_INACTIVE; -} - -KS_DECLARE(ks_size_t) ks_q_size(ks_q_t *q) -{ - ks_size_t size; - - ks_mutex_lock(q->list_mutex); - size = q->len; - ks_mutex_unlock(q->list_mutex); - - return size; -} - -KS_DECLARE(ks_status_t) ks_q_destroy(ks_q_t **qP) -{ - ks_q_t *q; - - ks_assert(qP); - - q = *qP; - *qP = NULL; - - if (q) { - ks_q_flush(q); - ks_q_term(q); - - ks_pool_free(&q); - - return KS_STATUS_SUCCESS; - } - - return KS_STATUS_FAIL; -} - -KS_DECLARE(ks_status_t) ks_q_create(ks_q_t **qP, ks_pool_t *pool, ks_size_t maxlen) -{ - ks_q_t *q = NULL; - - q = ks_pool_alloc(pool, sizeof(*q)); - ks_assert(q); - - ks_mutex_create(&q->list_mutex, KS_MUTEX_FLAG_DEFAULT, pool); - ks_assert(q->list_mutex); - - ks_cond_create_ex(&q->pop_cond, pool, q->list_mutex); - ks_assert(q->pop_cond); - - ks_cond_create_ex(&q->push_cond, pool, q->list_mutex); - ks_assert(q->push_cond); - - q->maxlen = maxlen; - q->active = 1; - - ks_pool_set_cleanup(q, NULL, ks_q_cleanup); - - *qP = q; - - return KS_STATUS_SUCCESS; -} - -static ks_qnode_t *new_node(ks_q_t *q) -{ - ks_qnode_t *np; - - if (q->empty) { - np = q->empty; - q->empty = q->empty->next; - } else { - np = ks_pool_alloc(ks_pool_get(q), sizeof(*np)); - } - - np->prev = np->next = NULL; - np->ptr = NULL; - - return np; -} - -static ks_status_t do_push(ks_q_t *q, void *ptr) -{ - ks_qnode_t *node; - - ks_mutex_lock(q->list_mutex); - - if (!q->active) { - ks_mutex_unlock(q->list_mutex); - return KS_STATUS_INACTIVE; - } - - node = new_node(q); - node->ptr = ptr; - - if (!q->head) { - q->head = q->tail = node; - } else { - q->tail->next = node; - node->prev = q->tail; - q->tail = node; - } - q->len++; - ks_mutex_unlock(q->list_mutex); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(ks_status_t) ks_q_push(ks_q_t *q, void *ptr) -{ - ks_status_t r; - - ks_mutex_lock(q->list_mutex); - if (q->active == 0) { - r = KS_STATUS_INACTIVE; - goto end; - } - - - if (q->maxlen && q->len == q->maxlen) { - q->pushers++; - ks_cond_wait(q->push_cond); - q->pushers--; - - if (q->maxlen && q->len == q->maxlen) { - if (!q->active) { - r = KS_STATUS_INACTIVE; - } else { - r = KS_STATUS_BREAK; - } - goto end; - } - } - - r = do_push(q, ptr); - - if (q->poppers) { - ks_cond_signal(q->pop_cond); - } - - end: - - ks_mutex_unlock(q->list_mutex); - return r; -} - -KS_DECLARE(ks_status_t) ks_q_trypush(ks_q_t *q, void *ptr) -{ - ks_status_t r; - - ks_mutex_lock(q->list_mutex); - if (q->active == 0) { - r = KS_STATUS_INACTIVE; - goto end; - } - - if (q->maxlen && q->len == q->maxlen) { - r = KS_STATUS_BREAK; - goto end; - } - - r = do_push(q, ptr); - - if (q->poppers) { - ks_cond_signal(q->pop_cond); - } - - end: - - ks_mutex_unlock(q->list_mutex); - - return r; -} - -static ks_status_t do_pop(ks_q_t *q, void **ptr) -{ - ks_qnode_t *np; - - ks_mutex_lock(q->list_mutex); - - if (!q->active) { - ks_mutex_unlock(q->list_mutex); - return KS_STATUS_INACTIVE; - } - - if (!q->head) { - *ptr = NULL; - } else { - np = q->head; - if ((q->head = q->head->next)) { - q->head->prev = NULL; - } - - *ptr = np->ptr; - - np->next = q->empty; - np->prev = NULL; - np->ptr = NULL; - q->empty = np; - } - - q->len--; - ks_mutex_unlock(q->list_mutex); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_q_pop_timeout(ks_q_t *q, void **ptr, uint32_t timeout) -{ - ks_status_t r; - - ks_mutex_lock(q->list_mutex); - - if (!q->active) { - r = KS_STATUS_INACTIVE; - goto end; - } - - if (q->len == 0) { - if (q->active) { - q->poppers++; - if (timeout) { - r = ks_cond_timedwait(q->pop_cond, timeout); - } else { - r = ks_cond_wait(q->pop_cond); - } - q->poppers--; - - if (timeout && r != KS_STATUS_SUCCESS) { - goto end; - } - } - - if (q->len == 0) { - if (!q->active) { - r = KS_STATUS_INACTIVE; - } else { - r = KS_STATUS_BREAK; - } - goto end; - } - } - - r = do_pop(q, ptr); - - if (q->pushers) { - ks_cond_signal(q->push_cond); - } - - end: - - ks_mutex_unlock(q->list_mutex); - - return r; - -} - -KS_DECLARE(ks_status_t) ks_q_pop(ks_q_t *q, void **ptr) -{ - return ks_q_pop_timeout(q, ptr, 0); -} - -KS_DECLARE(ks_status_t) ks_q_trypop(ks_q_t *q, void **ptr) -{ - ks_status_t r; - - ks_mutex_lock(q->list_mutex); - - if (!q->active) { - r = KS_STATUS_INACTIVE; - goto end; - } - - if (q->len == 0) { - r = KS_STATUS_BREAK; - goto end; - } - - r = do_pop(q, ptr); - - if (q->pushers) { - ks_cond_signal(q->push_cond); - } - - end: - - ks_mutex_unlock(q->list_mutex); - - return r; - -} - - - - -KS_DECLARE(ks_status_t) ks_q_wait(ks_q_t *q) -{ - ks_status_t r = KS_STATUS_SUCCESS; - int done = 0; - - do { - ks_mutex_lock(q->list_mutex); - - if (!q->active) { - r = KS_STATUS_INACTIVE; - done = 1; - } - - if (q->len == 0) { - done = 1; - } - - ks_mutex_unlock(q->list_mutex); - - } while (!done); - - return r; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_rng.c b/libs/libks/src/ks_rng.c deleted file mode 100644 index ada0c36f87..0000000000 --- a/libs/libks/src/ks_rng.c +++ /dev/null @@ -1,236 +0,0 @@ -/* - * Cross Platform random/uuid abstraction - * Copyright(C) 2015 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - -#include "ks.h" -#include -#include - -static ks_bool_t initialized = KS_FALSE; -static ks_mutex_t *rng_mutex = NULL; -static sha512_ctx global_sha512; - -#ifdef __WINDOWS__ -#include -HCRYPTPROV crypt_provider; -#else -int fd = -1; -#endif - -/* - * memset_volatile is a volatile pointer to the memset function. - * You can call (*memset_volatile)(buf, val, len) or even - * memset_volatile(buf, val, len) just as you would call - * memset(buf, val, len), but the use of a volatile pointer - * guarantees that the compiler will not optimise the call away. - */ -static void * (*volatile memset_volatile)(void *, int, size_t) = memset; - -KS_DECLARE(uuid_t *) ks_uuid(uuid_t *uuid) -{ -#ifdef __WINDOWS__ - UuidCreate ( uuid ); -#else - uuid_generate_random ( *uuid ); -#endif - return uuid; -} - -KS_DECLARE(char *) ks_uuid_str(ks_pool_t *pool, uuid_t *uuid) -{ - char *uuidstr = ks_pool_alloc(pool, 37); -#ifdef __WINDOWS__ - unsigned char * str; - UuidToStringA ( uuid, &str ); - uuidstr = ks_pstrdup(pool, (const char *)str); - RpcStringFreeA ( &str ); -#else - char str[37] = { 0 }; - uuid_unparse ( *uuid, str ); - uuidstr = ks_pstrdup(pool, str); -#endif - return uuidstr; -} - -KS_DECLARE(ks_status_t) ks_rng_init(void) -{ - if (!initialized) { - - - ks_aes_init(); - ks_mutex_create(&rng_mutex, KS_MUTEX_FLAG_DEFAULT, ks_global_pool()); -#ifdef __WINDOWS__ - if (!crypt_provider) { - if (CryptAcquireContext(&crypt_provider, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT) == TRUE) { - initialized = KS_TRUE; - } else { - initialized = KS_FALSE; - } - } -#else - if (fd < 0) { - fd = open("/dev/urandom", O_RDONLY); - if (fd < 0) { - fd = open("/dev/random", O_RDONLY); - } - } - initialized = KS_TRUE; -#endif - } - - sha512_begin(&global_sha512); - - if (initialized) { - return KS_STATUS_SUCCESS; - } else { - return KS_STATUS_FAIL; - } -} - -KS_DECLARE(ks_status_t) ks_rng_shutdown(void) -{ - - initialized = KS_FALSE; -#ifdef __WINDOWS__ - if (crypt_provider) { - CryptReleaseContext(crypt_provider, 0); - crypt_provider = 0; - } -#else - if (fd >= 0) { - close(fd); - fd = -1; - } -#endif - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(size_t) ks_rng_seed_data(uint8_t *seed, size_t length) -{ - size_t bytes = 0; - - if (!initialized && (ks_rng_init() != KS_STATUS_SUCCESS)) { - return bytes; - } -#ifdef __WINDOWS__ - if (crypt_provider) { - if(!CryptGenRandom(crypt_provider, (DWORD)length, seed)) { - return 0; - } - bytes = length; - } -#else - if (fd >= 0) { - bytes = read(fd, seed, length); - } else { - } -#endif - return bytes; -} - -KS_DECLARE(size_t) ks_rng_add_entropy(const uint8_t *buffer, size_t length) -{ - - uint8_t seed[64]; - size_t len = ks_rng_seed_data(seed, sizeof(seed)); - - ks_mutex_lock(rng_mutex); - - if (!initialized) { - ks_rng_init(); - } - - if (buffer && length) { - sha512_hash(buffer, (unsigned long)length, &global_sha512); - } - - if (len > 0) { - sha512_hash(seed, (unsigned long)len, &global_sha512); - length += len; - } - - ks_mutex_unlock(rng_mutex); - - return length; -} - -KS_DECLARE(size_t) ks_rng_get_data(uint8_t* buffer, size_t length) { - - aes_encrypt_ctx cx[1]; - sha512_ctx random_context; - uint8_t md[SHA512_DIGEST_SIZE]; - uint8_t ctr[AES_BLOCK_SIZE]; - uint8_t rdata[AES_BLOCK_SIZE]; - size_t generated = length; - - /* Add entropy from system state. We will include whatever happens to be in the buffer, it can't hurt */ - ks_rng_add_entropy(buffer, length); - - ks_mutex_lock(rng_mutex); - - /* Copy the mainCtx and finalize it into the md buffer */ - memcpy(&random_context, &global_sha512, sizeof(sha512_ctx)); - sha512_end(md, &random_context); - - ks_mutex_lock(rng_mutex); - - /* Key an AES context from this buffer */ - aes_encrypt_key256(md, cx); - - /* Initialize counter, using excess from md if available */ - memset (ctr, 0, sizeof(ctr)); - uint32_t ctrbytes = AES_BLOCK_SIZE; - memcpy(ctr + sizeof(ctr) - ctrbytes, md + 32, ctrbytes); - - /* Encrypt counter, copy to destination buffer, increment counter */ - while (length) { - uint8_t *ctrptr; - size_t copied; - aes_encrypt(ctr, rdata, cx); - copied = (sizeof(rdata) < length) ? sizeof(rdata) : length; - memcpy (buffer, rdata, copied); - buffer += copied; - length -= copied; - - /* Increment counter */ - ctrptr = ctr + sizeof(ctr) - 1; - while (ctrptr >= ctr) { - if ((*ctrptr-- += 1) != 0) { - break; - } - } - } - memset_volatile(&random_context, 0, sizeof(random_context)); - memset_volatile(md, 0, sizeof(md)); - memset_volatile(&cx, 0, sizeof(cx)); - memset_volatile(ctr, 0, sizeof(ctr)); - memset_volatile(rdata, 0, sizeof(rdata)); - - return generated; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_sb.c b/libs/libks/src/ks_sb.c deleted file mode 100644 index 4f9beacee5..0000000000 --- a/libs/libks/src/ks_sb.c +++ /dev/null @@ -1,227 +0,0 @@ -/* -* Copyright (c) 2017, Shane Bryldt -* All rights reserved. -* -* Redistribution and use in source and binary forms, with or without -* modification, are permitted provided that the following conditions -* are met: -* -* * Redistributions of source code must retain the above copyright -* notice, this list of conditions and the following disclaimer. -* -* * 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. -* -* * Neither the name of the original author; nor the names of any 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 "ks.h" -#include "ks_sb.h" - -struct ks_sb_s { - ks_bool_t pool_owner; - char *data; - ks_size_t size; - ks_size_t used; -}; - -static void ks_sb_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - ks_sb_t *sb = (ks_sb_t *)ptr; - - switch(action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - if (!sb->pool_owner && sb->data) ks_pool_free(&sb->data); - break; - case KS_MPCL_DESTROY: - break; - } - -} - -KS_DECLARE(ks_status_t) ks_sb_create(ks_sb_t **sbP, ks_pool_t *pool, ks_size_t preallocated) -{ - ks_sb_t *sb = NULL; - ks_bool_t pool_owner = KS_FALSE; - - ks_assert(sbP); - - if ((pool_owner = !pool)) ks_pool_open(&pool); - if (preallocated == 0) preallocated = KS_PRINT_BUF_SIZE * 2; - - sb = ks_pool_alloc(pool, sizeof(ks_sb_t)); - sb->pool_owner = pool_owner; - sb->data = ks_pool_alloc(pool, preallocated); - sb->size = preallocated; - sb->used = 1; - - ks_pool_set_cleanup(sb, NULL, ks_sb_cleanup); - - *sbP = sb; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_sb_destroy(ks_sb_t **sbP) -{ - ks_sb_t *sb = NULL; - - ks_assert(sbP); - ks_assert(*sbP); - - sb = *sbP; - *sbP = NULL; - - if (sb->pool_owner) { - ks_pool_t *pool = ks_pool_get(sb); - ks_pool_close(&pool); - } else ks_pool_free(sbP); - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(const char *) ks_sb_cstr(ks_sb_t *sb) -{ - ks_assert(sb); - return sb->data; -} - -KS_DECLARE(ks_size_t) ks_sb_length(ks_sb_t *sb) -{ - ks_assert(sb); - return sb->used - 1; -} - -KS_DECLARE(ks_status_t) ks_sb_accommodate(ks_sb_t *sb, ks_size_t len) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(sb); - - if (len == 0) goto done; - - if ((sb->used + len) > sb->size) { - ks_size_t needed = (sb->used + len) - sb->size; - if (needed < KS_PRINT_BUF_SIZE) needed = KS_PRINT_BUF_SIZE; - sb->size += needed; - if (!sb->data) sb->data = ks_pool_alloc(ks_pool_get(sb), sb->size); - else { - sb->data = ks_pool_resize(sb->data, sb->size); - if (!sb->data) ret = KS_STATUS_FAIL; - } - } - -done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_sb_append(ks_sb_t *sb, const char *str) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(sb); - - if (str) ret = ks_sb_append_ex(sb, str, strlen(str)); - - return ret; -} - -KS_DECLARE(ks_status_t) ks_sb_append_ex(ks_sb_t *sb, const char *str, ks_size_t len) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(sb); - - if (!str || len == 0) goto done; - - if (ks_sb_accommodate(sb, len) != KS_STATUS_SUCCESS) { - ret = KS_STATUS_FAIL; - goto done; - } - - memcpy(sb->data + (sb->used - 1), str, len + 1); - sb->used += len; - -done: - - return ret; -} - -KS_DECLARE(ks_status_t) ks_sb_printf(ks_sb_t *sb, const char *fmt, ...) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - va_list ap; - ks_size_t used = 0; - char *result = NULL; - - ks_assert(sb); - ks_assert(fmt); - - used = sb->used - 1; - - if (ks_sb_accommodate(sb, KS_PRINT_BUF_SIZE) != KS_STATUS_SUCCESS) { - ret = KS_STATUS_FAIL; - goto done; - } - - va_start(ap, fmt); - result = ks_vsnprintfv(sb->data + used, (int)(sb->size - used), fmt, ap); - va_end(ap); - - sb->used += strlen(result); - -done: - return ret; -} - -KS_DECLARE(ks_status_t) ks_sb_json(ks_sb_t *sb, const cJSON *json) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - char *str = NULL; - - ks_assert(sb); - ks_assert(json); - - str = cJSON_Print(json); - if (!str) { - ret = KS_STATUS_FAIL; - goto done; - } - - ks_sb_append(sb, str); - -done: - if (str) free(str); - - return ret; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_socket.c b/libs/libks/src/ks_socket.c deleted file mode 100644 index c98fad2518..0000000000 --- a/libs/libks/src/ks_socket.c +++ /dev/null @@ -1,1055 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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. - */ - - -/* Use select on windows and poll everywhere else. - Select is the devil. Especially if you are doing a lot of small socket connections. - If your FD number is bigger than 1024 you will silently create memory corruption. - - If you have build errors on your platform because you don't have poll find a way to detect it and #define KS_USE_SELECT and #undef KS_USE_POLL - All of this will be upgraded to autoheadache eventually. -*/ - -/* TBD for win32 figure out how to tell if you have WSAPoll (vista or higher) and use it when available by #defining KS_USE_WSAPOLL (see below) */ - -#ifdef _MSC_VER -#define FD_SETSIZE 8192 -//#define KS_USE_SELECT -#else -#define KS_USE_POLL -#endif - -#include - -#ifndef WIN32 -#define closesocket(s) close(s) -#else /* WIN32 */ - -#pragma warning (disable:6386) -/* These warnings need to be ignored warning in sdk header */ -#include -#include -#pragma comment(lib, "Ws2_32.lib") - -#ifndef errno -#define errno WSAGetLastError() -#endif - -#ifndef EINTR -#define EINTR WSAEINTR -#endif - -#pragma warning (default:6386) - -#endif /* WIN32 */ - -#ifndef SOL_IPV6 -#define SOL_IPV6 41 -#endif - -#ifdef KS_USE_POLL -#include -#endif - -KS_DECLARE(ks_status_t) ks_socket_option(ks_socket_t socket, int option_name, ks_bool_t enabled) -{ - int result = -1; - ks_status_t status = KS_STATUS_FAIL; -#ifdef WIN32 - BOOL opt = TRUE; - if (!enabled) opt = FALSE; -#else - int opt = 1; - if (!enabled) opt = 0; -#endif - - switch(option_name) { - case SO_REUSEADDR: - case TCP_NODELAY: - case SO_KEEPALIVE: - case SO_LINGER: -#ifdef WIN32 - result = setsockopt(socket, SOL_SOCKET, option_name, (char *) &opt, sizeof(opt)); -#else - result = setsockopt(socket, SOL_SOCKET, option_name, &opt, sizeof(opt)); -#endif - if (!result) status = KS_STATUS_SUCCESS; - break; - case KS_SO_NONBLOCK: - { -#ifdef WIN32 - u_long val = (u_long)!!opt; - if (ioctlsocket(socket, FIONBIO, &val) != SOCKET_ERROR) { - status = KS_STATUS_SUCCESS; - } -#else - int flags = fcntl(socket, F_GETFL, 0); - if (opt) { - flags |= O_NONBLOCK; - } else { - flags &= ~O_NONBLOCK; - } - if (fcntl(socket, F_SETFL, flags) != -1) { - status = KS_STATUS_SUCCESS; - } -#endif - } - break; - case IPV6_V6ONLY: -#ifdef WIN32 -//#warning make sure windows works like linux for IPV6 to IPV4 automapping stuff - result = setsockopt(socket, IPPROTO_IPV6, IPV6_V6ONLY, (char *)&opt, sizeof(opt)); -#else - result = setsockopt(socket, SOL_IPV6, IPV6_V6ONLY, &opt, sizeof(opt)); -#endif - if (!result) status = KS_STATUS_SUCCESS; - break; - default: - break; - } - - return status; -} - -KS_DECLARE(ks_status_t) ks_socket_sndbuf(ks_socket_t socket, int bufsize) -{ - int result; - ks_status_t status = KS_STATUS_FAIL; - -#ifdef WIN32 - result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, (char *) &bufsize, sizeof(bufsize)); -#else - result = setsockopt(socket, SOL_SOCKET, SO_SNDBUF, &bufsize, sizeof(bufsize)); -#endif - if (!result) status = KS_STATUS_SUCCESS; - - return status; -} - -KS_DECLARE(ks_status_t) ks_socket_rcvbuf(ks_socket_t socket, int bufsize) -{ - int result; - ks_status_t status = KS_STATUS_FAIL; - -#ifdef WIN32 - result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, (char *) &bufsize, sizeof(bufsize)); -#else - result = setsockopt(socket, SOL_SOCKET, SO_RCVBUF, &bufsize, sizeof(bufsize)); -#endif - if (!result) status = KS_STATUS_SUCCESS; - - return status; -} - -static int ks_socket_reuseaddr(ks_socket_t socket) -{ -#ifdef WIN32 - BOOL reuse_addr = TRUE; - return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, (char *) &reuse_addr, sizeof(reuse_addr)); -#else - int reuse_addr = 1; - return setsockopt(socket, SOL_SOCKET, SO_REUSEADDR, &reuse_addr, sizeof(reuse_addr)); -#endif -} - -KS_DECLARE(ks_status_t) ks_socket_shutdown(ks_socket_t sock, int how) -{ - return shutdown(sock, how) ? KS_STATUS_FAIL : KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_socket_close(ks_socket_t *sock) -{ - ks_assert(sock); - - if (*sock != KS_SOCK_INVALID) { - closesocket(*sock); - *sock = KS_SOCK_INVALID; - return KS_STATUS_SUCCESS; - } - - return KS_STATUS_FAIL; -} - -KS_DECLARE(ks_socket_t) ks_socket_connect(int type, int protocol, ks_sockaddr_t *addr) -{ - ks_socket_t sock = KS_SOCK_INVALID; - - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - if ((sock = socket(addr->family, type, protocol)) == KS_SOCK_INVALID) { - return KS_SOCK_INVALID; - } - - if (addr->family == AF_INET) { - if (connect(sock, (struct sockaddr *)&addr->v.v4, sizeof(addr->v.v4))) { - ks_socket_close(&sock); - return KS_SOCK_INVALID; - } - } else { - if (connect(sock, (struct sockaddr *)&addr->v.v6, sizeof(addr->v.v6))) { - ks_socket_close(&sock); - return KS_SOCK_INVALID; - } - } - - return sock; -} - -KS_DECLARE(ks_status_t) ks_addr_bind(ks_socket_t server_sock, const ks_sockaddr_t *addr) -{ - ks_status_t status = KS_STATUS_SUCCESS; - - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - if (addr->family == AF_INET) { - if (bind(server_sock, (struct sockaddr *) &addr->v.v4, sizeof(addr->v.v4)) < 0) { - status = KS_STATUS_FAIL; - } - } else { - if (bind(server_sock, (struct sockaddr *) &addr->v.v6, sizeof(addr->v.v6)) < 0) { - status = KS_STATUS_FAIL; - } - } - - return status; -} - -KS_DECLARE(const char *) ks_addr_get_host(ks_sockaddr_t *addr) -{ - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - if (addr->family == AF_INET) { - inet_ntop(AF_INET, &addr->v.v4.sin_addr, addr->host, sizeof(addr->host)); - } else { - inet_ntop(AF_INET6, &addr->v.v6.sin6_addr, addr->host, sizeof(addr->host)); - } - - return (const char *) addr->host; -} - -KS_DECLARE(ks_port_t) ks_addr_get_port(ks_sockaddr_t *addr) -{ - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - if (addr->family == AF_INET) { - addr->port = ntohs(addr->v.v4.sin_port); - } else { - addr->port = ntohs(addr->v.v6.sin6_port); - } - - return addr->port; -} - -KS_DECLARE(int) ks_addr_cmp(const ks_sockaddr_t *sa1, const ks_sockaddr_t *sa2) -{ - - if (!(sa1 && sa2)) { - return 0; - } - - if (sa1->family != sa2->family) { - return 0; - } - - switch (sa1->family) { - case AF_INET: - return (sa1->v.v4.sin_addr.s_addr == sa2->v.v4.sin_addr.s_addr && sa1->v.v4.sin_port == sa2->v.v4.sin_port); - case AF_INET6: - { - int i; - - if (sa1->v.v6.sin6_port != sa2->v.v6.sin6_port) { - return 0; - } - - for (i = 0; i < 4; i++) { - if (*((int32_t *) &sa1->v.v6.sin6_addr + i) != *((int32_t *) &sa2->v.v6.sin6_addr + i)) { - return 0; - } - } - - return 1; - } - } - - return 0; -} - -KS_DECLARE(ks_status_t) ks_addr_copy(ks_sockaddr_t *addr, const ks_sockaddr_t *src_addr) -{ - ks_status_t status = KS_STATUS_SUCCESS; - - ks_assert(addr); - ks_assert(src_addr); - ks_assert(src_addr->family == AF_INET || src_addr->family == AF_INET6); - - addr->family = src_addr->family; - - if (src_addr->family == AF_INET) { - memcpy(&addr->v.v4, &src_addr->v.v4, sizeof(src_addr->v.v4)); - } else { - memcpy(&addr->v.v6, &src_addr->v.v6, sizeof(src_addr->v.v6)); - } - - ks_addr_get_host(addr); - ks_addr_get_port(addr); - - return status; -} - - -KS_DECLARE(ks_status_t) ks_addr_set(ks_sockaddr_t *addr, const char *host, ks_port_t port, int family) -{ - ks_status_t status = KS_STATUS_SUCCESS; - - ks_assert(addr); - - if (family != PF_INET && family != PF_INET6) family = PF_INET; - if (host && strchr(host, ':')) family = PF_INET6; - - memset(addr, 0, sizeof(*addr)); - - if (family == PF_INET) { - addr->family = AF_INET; - addr->v.v4.sin_family = AF_INET; - addr->v.v4.sin_addr.s_addr = host ? inet_addr(host): htonl(INADDR_ANY); - addr->v.v4.sin_port = htons(port); - } else { - addr->family = AF_INET6; - addr->v.v6.sin6_family = AF_INET6; - addr->v.v6.sin6_port = htons(port); - if (host) { - inet_pton(AF_INET6, host, &(addr->v.v6.sin6_addr)); - } else { - addr->v.v6.sin6_addr = in6addr_any; - } - } - - ks_addr_get_host(addr); - ks_addr_get_port(addr); - - return status; -} - - -KS_DECLARE(ks_status_t) ks_addr_set_raw(ks_sockaddr_t *addr, const void *data, ks_port_t port, int family) -{ - ks_status_t status = KS_STATUS_SUCCESS; - - ks_assert(addr); - - if (family != PF_INET && family != PF_INET6) family = PF_INET; - - memset(addr, 0, sizeof(*addr)); - - if (family == PF_INET) { - addr->family = AF_INET; - addr->v.v4.sin_family = AF_INET; - memcpy(&(addr->v.v4.sin_addr), data, 4); - addr->v.v4.sin_port = port; - } else { - addr->family = AF_INET6; - addr->v.v6.sin6_family = AF_INET6; - addr->v.v6.sin6_port = port; - memcpy(&(addr->v.v6.sin6_addr), data, 16); - } - - ks_addr_get_host(addr); - ks_addr_get_port(addr); - - return status; -} - - -KS_DECLARE(ks_status_t) ks_listen_sock(ks_socket_t server_sock, ks_sockaddr_t *addr, int backlog, ks_listen_callback_t callback, void *user_data) -{ - ks_status_t status = KS_STATUS_SUCCESS; - - - ks_socket_reuseaddr(server_sock); - - if (ks_addr_bind(server_sock, addr) != KS_STATUS_SUCCESS) { - status = KS_STATUS_FAIL; - goto end; - } - - if (!backlog) backlog = 10000; - - if (listen(server_sock, backlog) < 0) { - status = KS_STATUS_FAIL; - goto end; - } - - for (;;) { - ks_socket_t client_sock; - ks_sockaddr_t remote_addr; - socklen_t slen = 0; - - if (addr->family == PF_INET) { - slen = sizeof(remote_addr.v.v4); - if ((client_sock = accept(server_sock, (struct sockaddr *) &remote_addr.v.v4, &slen)) == KS_SOCK_INVALID) { - status = KS_STATUS_FAIL; - goto end; - } - remote_addr.family = AF_INET; - } else { - slen = sizeof(remote_addr.v.v6); - if ((client_sock = accept(server_sock, (struct sockaddr *) &remote_addr.v.v6, &slen)) == KS_SOCK_INVALID) { - status = KS_STATUS_FAIL; - goto end; - } - remote_addr.family = AF_INET6; - } - - ks_addr_get_host(&remote_addr); - ks_addr_get_port(&remote_addr); - - callback(server_sock, client_sock, &remote_addr, user_data); - } - - end: - - if (server_sock != KS_SOCK_INVALID) { - ks_socket_shutdown(server_sock, 2); - ks_socket_close(&server_sock); - server_sock = KS_SOCK_INVALID; - } - - return status; -} - -KS_DECLARE(ks_status_t) ks_listen(const char *host, ks_port_t port, int family, int backlog, ks_listen_callback_t callback, void *user_data) -{ - ks_socket_t server_sock = KS_SOCK_INVALID; - ks_sockaddr_t addr = { 0 }; - - if (family != PF_INET && family != PF_INET6) family = PF_INET; - if (host && strchr(host, ':')) family = PF_INET6; - - if (ks_addr_set(&addr, host, port, family) != KS_STATUS_SUCCESS) { - return KS_STATUS_FAIL; - } - - if ((server_sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) { - return KS_STATUS_FAIL; - } - - return ks_listen_sock(server_sock, &addr, backlog, callback, user_data); -} - -KS_DECLARE(int) ks_poll(struct pollfd fds[], uint32_t nfds, int timeout) -{ -#ifdef WIN32 - return WSAPoll(fds, nfds, timeout); -#else - return poll(fds, nfds, timeout); -#endif -} - -#ifdef KS_USE_SELECT -#ifdef WIN32 -#pragma warning( push ) -#pragma warning( disable : 6262 ) /* warning C6262: Function uses '98348' bytes of stack: exceeds /analyze:stacksize'16384'. Consider moving some data to heap */ -#endif -KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags) -{ - int s = 0, r = 0; - fd_set rfds; - fd_set wfds; - fd_set efds; - struct timeval tv; - - FD_ZERO(&rfds); - FD_ZERO(&wfds); - FD_ZERO(&efds); - -#ifndef WIN32 - /* Wouldn't you rather know?? */ - assert(sock <= FD_SETSIZE); -#endif - - if ((flags & KS_POLL_READ)) { - -#ifdef WIN32 -#pragma warning( push ) -#pragma warning( disable : 4127 ) -#pragma warning( disable : 4548 ) - FD_SET(sock, &rfds); -#pragma warning( pop ) -#else - FD_SET(sock, &rfds); -#endif - } - - if ((flags & KS_POLL_WRITE)) { - -#ifdef WIN32 -#pragma warning( push ) -#pragma warning( disable : 4127 ) -#pragma warning( disable : 4548 ) - FD_SET(sock, &wfds); -#pragma warning( pop ) -#else - FD_SET(sock, &wfds); -#endif - } - - if ((flags & KS_POLL_ERROR)) { - -#ifdef WIN32 -#pragma warning( push ) -#pragma warning( disable : 4127 ) -#pragma warning( disable : 4548 ) - FD_SET(sock, &efds); -#pragma warning( pop ) -#else - FD_SET(sock, &efds); -#endif - } - - tv.tv_sec = ms / 1000; - tv.tv_usec = (ms % 1000) * ms; - - s = select((int)sock + 1, (flags & KS_POLL_READ) ? &rfds : NULL, (flags & KS_POLL_WRITE) ? &wfds : NULL, (flags & KS_POLL_ERROR) ? &efds : NULL, &tv); - - if (s < 0) { - r = s; - } else if (s > 0) { - if ((flags & KS_POLL_READ) && FD_ISSET(sock, &rfds)) { - r |= KS_POLL_READ; - } - - if ((flags & KS_POLL_WRITE) && FD_ISSET(sock, &wfds)) { - r |= KS_POLL_WRITE; - } - - if ((flags & KS_POLL_ERROR) && FD_ISSET(sock, &efds)) { - r |= KS_POLL_ERROR; - } - } - - return r; - -} - -#ifdef WIN32 -#pragma warning( pop ) -#endif -#endif - -#if defined(KS_USE_POLL) || defined(WIN32) -KS_DECLARE(int) ks_wait_sock(ks_socket_t sock, uint32_t ms, ks_poll_t flags) -{ - struct pollfd pfds[2] = { {0} }; - int s = 0, r = 0; - - pfds[0].fd = sock; - - if ((flags & KS_POLL_READ)) { - pfds[0].events |= POLLIN; - } - - if ((flags & KS_POLL_WRITE)) { - pfds[0].events |= POLLOUT; - } - - if ((flags & KS_POLL_ERROR)) { - pfds[0].events |= POLLERR; - } - - s = ks_poll(pfds, 1, ms); - - if (s < 0) { - r = s; - } else if (s > 0) { - if ((pfds[0].revents & POLLIN)) { - r |= KS_POLL_READ; - } - if ((pfds[0].revents & POLLOUT)) { - r |= KS_POLL_WRITE; - } - if ((pfds[0].revents & POLLERR)) { - r |= KS_POLL_ERROR; - } - } - - return r; - -} -#endif - - -#ifdef HAVE_GETIFADDRS -#include -static int get_netmask(struct sockaddr_in *me, int *mask) -{ - struct ifaddrs *ifaddrs, *i = NULL; - - if (!me || getifaddrs(&ifaddrs) < 0) { - return -1; - } - - for (i = ifaddrs; i; i = i->ifa_next) { - struct sockaddr_in *s = (struct sockaddr_in *) i->ifa_addr; - struct sockaddr_in *m = (struct sockaddr_in *) i->ifa_netmask; - - if (s && m && s->sin_family == AF_INET && s->sin_addr.s_addr == me->sin_addr.s_addr) { - *mask = m->sin_addr.s_addr; - freeifaddrs(ifaddrs); - return 0; - } - } - - freeifaddrs(ifaddrs); - - return -2; -} -#elif defined(__linux__) - -#include -#include -static int get_netmask(struct sockaddr_in *me, int *mask) -{ - - static struct ifreq ifreqs[20] = { {{{0}}} }; - struct ifconf ifconf; - int nifaces, i; - int sock; - int r = -1; - - memset(&ifconf, 0, sizeof(ifconf)); - ifconf.ifc_buf = (char *) (ifreqs); - ifconf.ifc_len = sizeof(ifreqs); - - - if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0) { - goto end; - } - - if (ioctl(sock, SIOCGIFCONF, (char *) &ifconf) < 0) { - goto end; - } - - nifaces = ifconf.ifc_len / sizeof(struct ifreq); - - for (i = 0; i < nifaces; i++) { - struct sockaddr_in *sin = NULL; - struct in_addr ip; - - ioctl(sock, SIOCGIFADDR, &ifreqs[i]); - sin = (struct sockaddr_in *) &ifreqs[i].ifr_addr; - ip = sin->sin_addr; - - if (ip.s_addr == me->sin_addr.s_addr) { - ioctl(sock, SIOCGIFNETMASK, &ifreqs[i]); - sin = (struct sockaddr_in *) &ifreqs[i].ifr_addr; - /* mask = sin->sin_addr; */ - *mask = sin->sin_addr.s_addr; - r = 0; - break; - } - - } - - end: - - close(sock); - return r; - -} - -#elif defined(WIN32) - -static int get_netmask(struct sockaddr_in *me, int *mask) -{ - SOCKET sock = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0); - INTERFACE_INFO interfaces[20]; - unsigned long bytes; - int interface_count, x; - int r = -1; - - *mask = 0; - - if (sock == SOCKET_ERROR) { - return -1; - } - - if (WSAIoctl(sock, SIO_GET_INTERFACE_LIST, 0, 0, &interfaces, sizeof(interfaces), &bytes, 0, 0) == SOCKET_ERROR) { - r = -1; - goto end; - } - - interface_count = bytes / sizeof(INTERFACE_INFO); - - for (x = 0; x < interface_count; ++x) { - struct sockaddr_in *addr = (struct sockaddr_in *) &(interfaces[x].iiAddress); - - if (addr->sin_addr.s_addr == me->sin_addr.s_addr) { - struct sockaddr_in *netmask = (struct sockaddr_in *) &(interfaces[x].iiNetmask); - *mask = netmask->sin_addr.s_addr; - r = 0; - break; - } - } - - end: - closesocket(sock); - return r; -} - -#else - -static int get_netmask(struct sockaddr_in *me, int *mask) -{ - return -1; -} - -#endif - - -KS_DECLARE(ks_status_t) ks_ip_route(char *buf, int len, const char *route_ip) -{ - int family = AF_INET; - - ks_assert(route_ip); - - if (strchr(route_ip, ':')) { - family = AF_INET6; - } - - return ks_find_local_ip(buf, len, NULL, family, route_ip); -} - -KS_DECLARE(ks_status_t) ks_find_local_ip(char *buf, int len, int *mask, int family, const char *route_ip) -{ - ks_status_t status = KS_STATUS_FAIL; - char *base = (char *)route_ip; - -#ifdef WIN32 - SOCKET tmp_socket; - SOCKADDR_STORAGE l_address; - int l_address_len; - struct addrinfo *address_info = NULL; -#else -#ifdef __Darwin__ - int ilen; -#else - unsigned int ilen; -#endif - int tmp_socket = -1, on = 1; - char abuf[25] = ""; -#endif - - if (len < 16) { - return status; - } - - switch (family) { - case AF_INET: - ks_copy_string(buf, "127.0.0.1", len); - if (!base) { - base = "82.45.148.209"; - } - break; - case AF_INET6: - ks_copy_string(buf, "::1", len); - if (!base) { - base = "2001:503:BA3E::2:30"; /* DNS Root server A */ - } - break; - default: - base = "127.0.0.1"; - break; - } - -#ifdef WIN32 - tmp_socket = socket(family, SOCK_DGRAM, 0); - - getaddrinfo(base, NULL, NULL, &address_info); - - if (!address_info || WSAIoctl(tmp_socket, - SIO_ROUTING_INTERFACE_QUERY, - address_info->ai_addr, (DWORD) address_info->ai_addrlen, &l_address, sizeof(l_address), (LPDWORD) & l_address_len, NULL, - NULL)) { - - closesocket(tmp_socket); - if (address_info) - freeaddrinfo(address_info); - return status; - } - - - closesocket(tmp_socket); - freeaddrinfo(address_info); - - if (!getnameinfo((const struct sockaddr *) &l_address, l_address_len, buf, len, NULL, 0, NI_NUMERICHOST)) { - status = KS_STATUS_SUCCESS; - if (mask && family == AF_INET) { - get_netmask((struct sockaddr_in *) &l_address, mask); - } - } -#else - - switch (family) { - case AF_INET: - { - struct sockaddr_in iface_out; - struct sockaddr_in remote; - memset(&remote, 0, sizeof(struct sockaddr_in)); - - remote.sin_family = AF_INET; - remote.sin_addr.s_addr = inet_addr(base); - remote.sin_port = htons(4242); - - memset(&iface_out, 0, sizeof(iface_out)); - if ( (tmp_socket = socket(AF_INET, SOCK_DGRAM, 0)) == -1 ) { - goto doh; - } - - if (setsockopt(tmp_socket, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on)) == -1) { - goto doh; - } - - if (connect(tmp_socket, (struct sockaddr *) &remote, sizeof(struct sockaddr_in)) == -1) { - goto doh; - } - - ilen = sizeof(iface_out); - if (getsockname(tmp_socket, (struct sockaddr *) &iface_out, &ilen) == -1) { - goto doh; - } - - if (iface_out.sin_addr.s_addr == 0) { - goto doh; - } - - getnameinfo((struct sockaddr *) &iface_out, sizeof(iface_out), abuf, sizeof(abuf), NULL, 0, NI_NUMERICHOST); - ks_copy_string(buf, abuf, len); - - if (mask && family == AF_INET) { - get_netmask((struct sockaddr_in *) &iface_out, mask); - } - - status = KS_STATUS_SUCCESS; - } - break; - case AF_INET6: - { - struct sockaddr_in6 iface_out; - struct sockaddr_in6 remote; - memset(&remote, 0, sizeof(struct sockaddr_in6)); - - remote.sin6_family = AF_INET6; - inet_pton(AF_INET6, base, &remote.sin6_addr); - remote.sin6_port = htons(4242); - - memset(&iface_out, 0, sizeof(iface_out)); - if ( (tmp_socket = socket(AF_INET6, SOCK_DGRAM, 0)) == -1 ) { - goto doh; - } - - if (connect(tmp_socket, (struct sockaddr *) &remote, sizeof(remote)) == -1) { - goto doh; - } - - ilen = sizeof(iface_out); - if (getsockname(tmp_socket, (struct sockaddr *) &iface_out, &ilen) == -1) { - goto doh; - } - - inet_ntop(AF_INET6, (const void *) &iface_out.sin6_addr, buf, len - 1); - - status = KS_STATUS_SUCCESS; - } - break; - } - - doh: - if (tmp_socket > 0) { - close(tmp_socket); - } -#endif - - return status; -} - - -KS_DECLARE(ks_status_t) ks_addr_raw_data(const ks_sockaddr_t *addr, void **data, ks_size_t *datalen) -{ - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - if (addr->family == AF_INET) { - *data = (void *)&addr->v.v4.sin_addr; - *datalen = 4; - } else { - *data = (void *)&addr->v.v6.sin6_addr; - *datalen = 16; - } - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_socket_send(ks_socket_t sock, void *data, ks_size_t *datalen) -{ - ks_ssize_t r; - ks_status_t status = KS_STATUS_FAIL; - - do { -#ifdef WIN32 - r = send(sock, data, (int)*datalen, 0); -#else - r = send(sock, data, *datalen, 0); -#endif - } while (r == -1 && ks_errno_is_interupt(ks_errno())); - - if (r > 0) { - *datalen = (ks_size_t) r; - status = KS_STATUS_SUCCESS; - } else if (r == 0) { - status = KS_STATUS_DISCONNECTED; - - } else if (ks_errno_is_blocking(ks_errno())) { - status = KS_STATUS_BREAK; - } - -return status; -} - -KS_DECLARE(ks_status_t) ks_socket_recv(ks_socket_t sock, void *data, ks_size_t *datalen) -{ - ks_ssize_t r; - ks_status_t status = KS_STATUS_FAIL; - - do { -#ifdef WIN32 - r = recv(sock, data, (int)*datalen, 0); -#else - r = recv(sock, data, *datalen, 0); -#endif - } while (r == -1 && ks_errno_is_interupt(ks_errno())); - - if (r > 0) { - *datalen = (ks_size_t) r; - status = KS_STATUS_SUCCESS; - } else if (r == 0) { - status = KS_STATUS_DISCONNECTED; - } else if (ks_errno_is_blocking(ks_errno())) { - status = KS_STATUS_BREAK; - } - - return status; -} - -KS_DECLARE(ks_status_t) ks_socket_sendto(ks_socket_t sock, void *data, ks_size_t *datalen, ks_sockaddr_t *addr) -{ - struct sockaddr *sockaddr; - socklen_t socksize = 0; - ks_status_t status = KS_STATUS_FAIL; - ks_ssize_t r; - - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - if (addr->family == AF_INET) { - sockaddr = (struct sockaddr *) &addr->v.v4; - socksize = sizeof(addr->v.v4); - } else { - sockaddr = (struct sockaddr *) &addr->v.v6; - socksize = sizeof(addr->v.v6); - } - - do { -#ifdef WIN32 - r = sendto(sock, data, (int)*datalen, 0, sockaddr, socksize); -#else - r = sendto(sock, data, *datalen, 0, sockaddr, socksize); -#endif - } while (r == -1 && ks_errno_is_interupt(ks_errno())); - - if (r > 0) { - *datalen = (ks_size_t) r; - status = KS_STATUS_SUCCESS; - } else if (r == 0) { - status = KS_STATUS_DISCONNECTED; - } else if (ks_errno_is_blocking(ks_errno())) { - status = KS_STATUS_BREAK; - } - - return status; - -} - -KS_DECLARE(ks_status_t) ks_socket_recvfrom(ks_socket_t sock, void *data, ks_size_t *datalen, ks_sockaddr_t *addr) -{ - struct sockaddr *sockaddr; - ks_status_t status = KS_STATUS_FAIL; - ks_ssize_t r; - socklen_t alen; - - ks_assert(addr); - ks_assert(addr->family == AF_INET || addr->family == AF_INET6); - - if (addr->family == AF_INET) { - sockaddr = (struct sockaddr *) &addr->v.v4; - alen = sizeof(addr->v.v4); - } else { - sockaddr = (struct sockaddr *) &addr->v.v6; - alen = sizeof(addr->v.v6); - } - - do { -#ifdef WIN32 - r = recvfrom(sock, data, (int)*datalen, 0, sockaddr, &alen); -#else - r = recvfrom(sock, data, *datalen, 0, sockaddr, &alen); -#endif - } while (r == -1 && ks_errno_is_interupt(ks_errno())); - - if (r > 0) { - ks_addr_get_host(addr); - ks_addr_get_port(addr); - *datalen = (ks_size_t) r; - status = KS_STATUS_SUCCESS; - } else if (r == 0) { - status = KS_STATUS_DISCONNECTED; - } else if (ks_errno_is_blocking(ks_errno())) { - status = KS_STATUS_BREAK; - } - - return status; -} - diff --git a/libs/libks/src/ks_ssl.c b/libs/libks/src/ks_ssl.c deleted file mode 100644 index 4f3efafd8f..0000000000 --- a/libs/libks/src/ks_ssl.c +++ /dev/null @@ -1,258 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - -static ks_mutex_t **ssl_mutexes; -static ks_pool_t *ssl_pool = NULL; -static int ssl_count = 0; -static int is_init = 0; - -static inline void ks_ssl_lock_callback(int mode, int type, char *file, int line) -{ - if (mode & CRYPTO_LOCK) { - ks_mutex_lock(ssl_mutexes[type]); - } - else { - ks_mutex_unlock(ssl_mutexes[type]); - } -} - -static inline unsigned long ks_ssl_thread_id(void) -{ - return ks_thread_self_id(); -} - -KS_DECLARE(void) ks_ssl_init_ssl_locks(void) -{ - - int i, num; - - if (is_init) return; - - is_init = 1; - - SSL_library_init(); - SSL_load_error_strings(); - - if (ssl_count == 0) { - num = CRYPTO_num_locks(); - - ssl_mutexes = OPENSSL_malloc(CRYPTO_num_locks() * sizeof(ks_mutex_t*)); - ks_assert(ssl_mutexes != NULL); - - ks_pool_open(&ssl_pool); - - for (i = 0; i < num; i++) { - ks_mutex_create(&(ssl_mutexes[i]), KS_MUTEX_FLAG_DEFAULT, ssl_pool); - ks_assert(ssl_mutexes[i] != NULL); - } - - CRYPTO_set_id_callback(ks_ssl_thread_id); - CRYPTO_set_locking_callback((void (*)(int, int, const char*, int))ks_ssl_lock_callback); - } - - ssl_count++; -} - -KS_DECLARE(void) ks_ssl_destroy_ssl_locks(void) -{ - int i; - - if (!is_init) return; - - is_init = 0; - - if (ssl_count == 1) { - CRYPTO_set_locking_callback(NULL); - for (i = 0; i < CRYPTO_num_locks(); i++) { - if (ssl_mutexes[i]) { - ks_mutex_destroy(&ssl_mutexes[i]); - } - } - - OPENSSL_free(ssl_mutexes); - ssl_count--; - if (ssl_pool) ks_pool_close(&ssl_pool); - } - -#ifdef _WINDOWS - SSL_COMP_free_compression_methods(); -#endif - ERR_free_strings(); - EVP_cleanup(); -} - - - -static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days); - -KS_DECLARE(int) ks_gen_cert(const char *dir, const char *file) -{ - //BIO *bio_err; - X509 *x509 = NULL; - EVP_PKEY *pkey = NULL; - char *rsa = NULL, *pvt = NULL; - FILE *fp; - char *pem = NULL; - - if (ks_stristr(".pem", file)) { - pem = ks_mprintf("%s%s%s", dir, KS_PATH_SEPARATOR, file); - } else { - pvt = ks_mprintf("%s%s%s.key", dir, KS_PATH_SEPARATOR, file); - rsa = ks_mprintf("%s%s%s.crt", dir, KS_PATH_SEPARATOR, file); - } - - CRYPTO_mem_ctrl(CRYPTO_MEM_CHECK_ON); - - //bio_err=BIO_new_fp(stderr, BIO_NOCLOSE); - - mkcert(&x509, &pkey, 1024, 0, 36500); - - //RSA_print_fp(stdout, pkey->pkey.rsa, 0); - //X509_print_fp(stdout, x509); - - if (pem) { - if ((fp = fopen(pem, "w"))) { - PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL); - PEM_write_X509(fp, x509); - fclose(fp); - } - - } else { - if (pvt && (fp = fopen(pvt, "w"))) { - PEM_write_PrivateKey(fp, pkey, NULL, NULL, 0, NULL, NULL); - fclose(fp); - } - - if (rsa && (fp = fopen(rsa, "w"))) { - PEM_write_X509(fp, x509); - fclose(fp); - } - } - - X509_free(x509); - EVP_PKEY_free(pkey); - -#ifndef OPENSSL_NO_ENGINE - ENGINE_cleanup(); -#endif - CRYPTO_cleanup_all_ex_data(); - - //CRYPTO_mem_leaks(bio_err); - //BIO_free(bio_err); - - - ks_safe_free(pvt); - ks_safe_free(rsa); - ks_safe_free(pem); - - return(0); -} - -static int mkcert(X509 **x509p, EVP_PKEY **pkeyp, int bits, int serial, int days) -{ - X509 *x; - EVP_PKEY *pk; - RSA *rsa; - X509_NAME *name=NULL; - - ks_assert(pkeyp); - ks_assert(x509p); - - if (*pkeyp == NULL) { - if ((pk = EVP_PKEY_new()) == NULL) { - abort(); - } - } else { - pk = *pkeyp; - } - - if (*x509p == NULL) { - if ((x = X509_new()) == NULL) { - goto err; - } - } else { - x = *x509p; - } - - rsa = RSA_generate_key(bits, RSA_F4, NULL, NULL); - - if (!EVP_PKEY_assign_RSA(pk, rsa)) { - abort(); - goto err; - } - - rsa = NULL; - - X509_set_version(x, 0); - ASN1_INTEGER_set(X509_get_serialNumber(x), serial); - X509_gmtime_adj(X509_get_notBefore(x), -(long)60*60*24*7); - X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); - X509_set_pubkey(x, pk); - - name = X509_get_subject_name(x); - - /* This function creates and adds the entry, working out the - * correct string type and performing checks on its length. - * Normally we'd check the return value for errors... - */ - X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC, (unsigned char *)"US", -1, -1, 0); - X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, (unsigned char *)"FreeSWITCH-libKS", -1, -1, 0); - - - /* Its self signed so set the issuer name to be the same as the - * subject. - */ - X509_set_issuer_name(x, name); - - if (!X509_sign(x, pk, EVP_sha1())) - goto err; - - *x509p = x; - *pkeyp = pk; - return(1); - err: - return(0); -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_string.c b/libs/libks/src/ks_string.c deleted file mode 100644 index 8ac3054cc6..0000000000 --- a/libs/libks/src/ks_string.c +++ /dev/null @@ -1,483 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - -#define ESCAPE_META '\\' - -/* Written by Marc Espie, public domain */ -#define KS_CTYPE_NUM_CHARS 256 - -const short _ks_C_toupper_[1 + KS_CTYPE_NUM_CHARS] = { - EOF, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, - 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, - 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, - 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', - 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', - 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', - 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff -}; - -const short *_ks_toupper_tab_ = _ks_C_toupper_; - -KS_DECLARE(int) ks_toupper(int c) -{ - if ((unsigned int) c > 255) - return (c); - if (c < -1) - return EOF; - return ((_ks_toupper_tab_ + 1)[c]); -} - -const short _ks_C_tolower_[1 + KS_CTYPE_NUM_CHARS] = { - EOF, - 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, - 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, - 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, - 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, - 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, - 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, - 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, - 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', - 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', - 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', - 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, - 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, - 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, - 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, - 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, - 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, - 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, - 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, - 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, - 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, - 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, - 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, - 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, - 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, - 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, - 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, - 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, - 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, - 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, - 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, - 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff -}; - -const short *_ks_tolower_tab_ = _ks_C_tolower_; - -KS_DECLARE(int) ks_tolower(int c) -{ - if ((unsigned int) c > 255) - return (c); - if (c < -1) - return EOF; - return ((_ks_tolower_tab_ + 1)[c]); -} - -KS_DECLARE(const char *) ks_stristr(const char *instr, const char *str) -{ -/* -** Rev History: 16/07/97 Greg Thayer Optimized -** 07/04/95 Bob Stout ANSI-fy -** 02/03/94 Fred Cole Original -** 09/01/03 Bob Stout Bug fix (lines 40-41) per Fred Bulback -** -** Hereby donated to public domain. -*/ - const char *pptr, *sptr, *start; - - if (!str || !instr) - return NULL; - - for (start = str; *start; start++) { - /* find start of pattern in string */ - for (; ((*start) && (ks_toupper(*start) != ks_toupper(*instr))); start++); - - if (!*start) - return NULL; - - pptr = instr; - sptr = start; - - while (ks_toupper(*sptr) == ks_toupper(*pptr)) { - sptr++; - pptr++; - - /* if end of pattern then pattern was found */ - if (!*pptr) - return (start); - - if (!*sptr) - return NULL; - } - } - return NULL; -} - -#ifdef WIN32 -#ifndef vsnprintf -#define vsnprintf _vsnprintf -#endif -#endif - - -int vasprintf(char **ret, const char *format, va_list ap); - -KS_DECLARE(int) ks_vasprintf(char **ret, const char *fmt, va_list ap) -{ -#if !defined(WIN32) && !defined(__sun) - return vasprintf(ret, fmt, ap); -#else - char *buf; - int len; - size_t buflen; - va_list ap2; - char *tmp = NULL; - -#ifdef _MSC_VER -#if _MSC_VER >= 1500 - /* hack for incorrect assumption in msvc header files for code analysis */ - __analysis_assume(tmp); -#endif - ap2 = ap; -#else - va_copy(ap2, ap); -#endif - - len = vsnprintf(tmp, 0, fmt, ap2); - - if (len > 0 && (buf = malloc((buflen = (size_t) (len + 1)))) != NULL) { - len = vsnprintf(buf, buflen, fmt, ap); - *ret = buf; - } else { - *ret = NULL; - len = -1; - } - - va_end(ap2); - return len; -#endif -} - - -KS_DECLARE(int) ks_snprintf(char *buffer, size_t count, const char *fmt, ...) -{ - va_list ap; - int ret; - - va_start(ap, fmt); - ret = vsnprintf(buffer, count - 1, fmt, ap); - if (ret < 0) - buffer[count - 1] = '\0'; - va_end(ap); - return ret; -} - - -/* Helper function used when separating strings to unescape a character. The - supported characters are: - - \n linefeed - \r carriage return - \t tab - \s space - - Any other character is returned as it was received. */ -static char unescape_char(char escaped) -{ - char unescaped; - - switch (escaped) { - case 'n': - unescaped = '\n'; - break; - case 'r': - unescaped = '\r'; - break; - case 't': - unescaped = '\t'; - break; - case 's': - unescaped = ' '; - break; - default: - unescaped = escaped; - } - return unescaped; -} - - -/* Helper function used when separating strings to remove quotes, leading / - trailing spaces, and to convert escaped characters. */ -static char *cleanup_separated_string(char *str, char delim) -{ - char *ptr; - char *dest; - char *start; - char *end = NULL; - int inside_quotes = 0; - - /* Skip initial whitespace */ - for (ptr = str; *ptr == ' '; ++ptr) { - } - - for (start = dest = ptr; *ptr; ++ptr) { - char e; - int esc = 0; - - if (*ptr == ESCAPE_META) { - e = *(ptr + 1); - if (e == '\'' || e == '"' || (delim && e == delim) || e == ESCAPE_META || (e = unescape_char(*(ptr + 1))) != *(ptr + 1)) { - ++ptr; - *dest++ = e; - end = dest; - esc++; - } - } - if (!esc) { - if (*ptr == '\'' && (inside_quotes || ((ptr+1) && strchr(ptr+1, '\'')))) { - if ((inside_quotes = (1 - inside_quotes))) { - end = dest; - } - } else { - *dest++ = *ptr; - if (*ptr != ' ' || inside_quotes) { - end = dest; - } - } - } - } - if (end) { - *end = '\0'; - } - - return start; -} - -KS_DECLARE(unsigned int) ks_separate_string_string(char *buf, const char *delim, char **array, unsigned int arraylen) -{ - unsigned int count = 0; - char *d; - size_t dlen = strlen(delim); - - array[count++] = buf; - - while (count < arraylen && array[count - 1]) { - if ((d = strstr(array[count - 1], delim))) { - *d = '\0'; - d += dlen; - array[count++] = d; - } else - break; - } - - return count; -} - -KS_DECLARE(char *) ks_copy_string(char *from_str, const char *to_str, ks_size_t from_str_len) -{ - char *p, *e; - - if (!from_str) - return NULL; - if (!to_str) { - *from_str = '\0'; - return from_str; - } - - e = from_str + from_str_len - 1; - - for (p = from_str; p < e; ++p, ++to_str) { - if (!(*p = *to_str)) { - return p; - } - } - - *p = '\0'; - - return p; -} - - -/* Separate a string using a delimiter that is not a space */ -static unsigned int separate_string_char_delim(char *buf, char delim, char **array, unsigned int arraylen) -{ - enum tokenizer_state { - START, - FIND_DELIM - } state = START; - - unsigned int count = 0; - char *ptr = buf; - int inside_quotes = 0; - unsigned int i; - - while (*ptr && count < arraylen) { - switch (state) { - case START: - array[count++] = ptr; - state = FIND_DELIM; - break; - - case FIND_DELIM: - /* escaped characters are copied verbatim to the destination string */ - if (*ptr == ESCAPE_META) { - ++ptr; - } else if (*ptr == '\'' && (inside_quotes || ((ptr+1) && strchr(ptr+1, '\'')))) { - inside_quotes = (1 - inside_quotes); - } else if (*ptr == delim && !inside_quotes) { - *ptr = '\0'; - state = START; - } - ++ptr; - break; - } - } - /* strip quotes, escaped chars and leading / trailing spaces */ - - for (i = 0; i < count; ++i) { - array[i] = cleanup_separated_string(array[i], delim); - } - - return count; -} - -/* Separate a string using a delimiter that is a space */ -static unsigned int separate_string_blank_delim(char *buf, char **array, unsigned int arraylen) -{ - enum tokenizer_state { - START, - SKIP_INITIAL_SPACE, - FIND_DELIM, - SKIP_ENDING_SPACE - } state = START; - - unsigned int count = 0; - char *ptr = buf; - int inside_quotes = 0; - unsigned int i; - - while (*ptr && count < arraylen) { - switch (state) { - case START: - array[count++] = ptr; - state = SKIP_INITIAL_SPACE; - break; - - case SKIP_INITIAL_SPACE: - if (*ptr == ' ') { - ++ptr; - } else { - state = FIND_DELIM; - } - break; - - case FIND_DELIM: - if (*ptr == ESCAPE_META) { - ++ptr; - } else if (*ptr == '\'') { - inside_quotes = (1 - inside_quotes); - } else if (*ptr == ' ' && !inside_quotes) { - *ptr = '\0'; - state = SKIP_ENDING_SPACE; - } - ++ptr; - break; - - case SKIP_ENDING_SPACE: - if (*ptr == ' ') { - ++ptr; - } else { - state = START; - } - break; - } - } - /* strip quotes, escaped chars and leading / trailing spaces */ - - for (i = 0; i < count; ++i) { - array[i] = cleanup_separated_string(array[i], 0); - } - - return count; -} - -KS_DECLARE(unsigned int) ks_separate_string(char *buf, char delim, char **array, unsigned int arraylen) -{ - if (!buf || !array || !arraylen) { - return 0; - } - - - if (*buf == '^' && *(buf+1) == '^') { - char *p = buf + 2; - - if (p && *p && *(p+1)) { - buf = p; - delim = *buf++; - } - } - - - memset(array, 0, arraylen * sizeof(*array)); - - return (delim == ' ' ? separate_string_blank_delim(buf, array, arraylen) : separate_string_char_delim(buf, delim, array, arraylen)); -} diff --git a/libs/libks/src/ks_thread.c b/libs/libks/src/ks_thread.c deleted file mode 100644 index 764a44a043..0000000000 --- a/libs/libks/src/ks_thread.c +++ /dev/null @@ -1,324 +0,0 @@ -/* - * Cross Platform Thread/Mutex abstraction - * Copyright(C) 2007 Michael Jerris - * - * You may opt to use, copy, modify, merge, publish, distribute and/or sell - * copies of the Software, and permit persons to whom the Software is - * furnished to do so. - * - * This work is provided under this license on an "as is" basis, without warranty of any kind, - * either expressed or implied, including, without limitation, warranties that the covered code - * is free of defects, merchantable, fit for a particular purpose or non-infringing. The entire - * risk as to the quality and performance of the covered code is with you. Should any covered - * code prove defective in any respect, you (not the initial developer or any other contributor) - * assume the cost of any necessary servicing, repair or correction. This disclaimer of warranty - * constitutes an essential part of this license. No use of any covered code is authorized hereunder - * except under this disclaimer. - * - */ - -#include "ks.h" - -size_t thread_default_stacksize = 240 * 1024; - -#ifndef WIN32 -pthread_once_t init_priority = PTHREAD_ONCE_INIT; -#endif - -KS_DECLARE(ks_thread_os_handle_t) ks_thread_os_handle(ks_thread_t *thread) -{ - return thread->handle; -} - -KS_DECLARE(ks_thread_os_handle_t) ks_thread_self(void) -{ -#ifdef WIN32 - return GetCurrentThread(); -#else - return pthread_self(); -#endif -} - -KS_DECLARE(ks_pid_t) ks_thread_self_id(void) -{ -#ifdef WIN32 - return GetCurrentThreadId(); -#elif gettid - return gettid(); -#else - return (ks_pid_t) pthread_self(); - //return syscall(SYS_gettid); -#endif -} - -static void ks_thread_init_priority(void) -{ -#ifdef WIN32 - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); -#else -#ifdef USE_SCHED_SETSCHEDULER - /* - * Try to use a round-robin scheduler - * with a fallback if that does not work - */ - struct sched_param sched = { 0 }; - sched.sched_priority = KS_PRI_LOW; - if (sched_setscheduler(0, SCHED_FIFO, &sched)) { - sched.sched_priority = 0; - if (sched_setscheduler(0, SCHED_OTHER, &sched)) { - return; - } - } -#endif -#endif - return; -} - -void ks_thread_override_default_stacksize(size_t size) -{ - thread_default_stacksize = size; -} - -static void ks_thread_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - ks_thread_t *thread = (ks_thread_t *) ptr; - - switch(action) { - case KS_MPCL_ANNOUNCE: - if (thread->state == KS_THREAD_RUNNING) { - thread->state = KS_THREAD_SHUTDOWN; - } - break; - case KS_MPCL_TEARDOWN: - while(thread->state == KS_THREAD_SHUTDOWN) { - ks_sleep(10000); - } - - if (!(thread->flags & KS_THREAD_FLAG_DETACHED)) { - ks_thread_join(thread); - } - break; - case KS_MPCL_DESTROY: - -#ifdef WIN32 - if (!(thread->flags & KS_THREAD_FLAG_DETACHED)) { - CloseHandle(thread->handle); - } -#endif - break; - } -} - -static void *KS_THREAD_CALLING_CONVENTION thread_launch(void *args) -{ - ks_thread_t *thread = (ks_thread_t *) args; - -#ifdef HAVE_PTHREAD_SETSCHEDPARAM - if (thread->priority) { - int policy = SCHED_FIFO; - struct sched_param param = { 0 }; - pthread_t tt = pthread_self(); - - pthread_once(&init_priority, ks_thread_init_priority); - pthread_getschedparam(tt, &policy, ¶m); - param.sched_priority = thread->priority; - pthread_setschedparam(tt, policy, ¶m); - } -#endif - thread->state = KS_THREAD_RUNNING; - thread->return_data = thread->function(thread, thread->private_data); - thread->state = KS_THREAD_STOPPED; -#ifndef WIN32 - pthread_attr_destroy(&thread->attribute); -#endif - - return thread->return_data; -} - -KS_DECLARE(int) ks_thread_set_priority(int nice_val) -{ -#ifdef WIN32 - SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS); -#else -#ifdef USE_SCHED_SETSCHEDULER - /* - * Try to use a round-robin scheduler - * with a fallback if that does not work - */ - struct sched_param sched = { 0 }; - sched.sched_priority = KS_PRI_LOW; - if (sched_setscheduler(0, SCHED_FIFO, &sched)) { - sched.sched_priority = 0; - if (sched_setscheduler(0, SCHED_OTHER, &sched)) { - return -1; - } - } -#endif - - if (nice_val) { -#ifdef HAVE_SETPRIORITY - /* - * setpriority() works on FreeBSD (6.2), nice() doesn't - */ - if (setpriority(PRIO_PROCESS, getpid(), nice_val) < 0) { - ks_log(KS_LOG_CRIT, "Could not set nice level\n"); - return -1; - } -#else - if (nice(nice_val) != nice_val) { - ks_log(KS_LOG_CRIT, "Could not set nice level\n"); - return -1; - } -#endif - } -#endif - - return 0; -} - -KS_DECLARE(uint8_t) ks_thread_priority(ks_thread_t *thread) { - uint8_t priority = 0; -#ifdef WIN32 - //int pri = GetThreadPriority(thread->handle); - - //if (pri >= THREAD_PRIORITY_TIME_CRITICAL) { - // priority = 99; - //} else if (pri >= THREAD_PRIORITY_ABOVE_NORMAL) { - // priority = 50; - //} else { - // priority = 10; - //} - priority = thread->priority; -#else - int policy; - struct sched_param param = { 0 }; - - pthread_getschedparam(thread->handle, &policy, ¶m); - priority = param.sched_priority; -#endif - return priority; -} - -KS_DECLARE(ks_status_t) ks_thread_join(ks_thread_t *thread) { - - if (thread->state == KS_THREAD_RUNNING) { - thread->state = KS_THREAD_SHUTDOWN; - } - - if (thread->joined) { - return KS_STATUS_DUPLICATE_OPERATION; - } - -#ifdef WIN32 - WaitForSingleObject(thread->handle, INFINITE); -#else - void *ret; - pthread_join(thread->handle, &ret); -#endif - - thread->joined++; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_thread_create_ex(ks_thread_t **rthread, ks_thread_function_t func, void *data, - uint32_t flags, size_t stack_size, ks_thread_priority_t priority, ks_pool_t *pool) -{ - ks_thread_t *thread = NULL; - ks_status_t status = KS_STATUS_FAIL; - int sanity = 1000; - - if (!rthread) goto done; - - *rthread = NULL; - - if (!func || !pool) goto done; - - thread = (ks_thread_t *) ks_pool_alloc(pool, sizeof(ks_thread_t)); - - if (!thread) goto done; - - thread->private_data = data; - thread->function = func; - thread->stack_size = stack_size; - thread->flags = flags; - thread->priority = priority; - -#if defined(WIN32) - thread->handle = (void *) _beginthreadex(NULL, (unsigned) thread->stack_size, (unsigned int (__stdcall *) (void *)) thread_launch, thread, 0, NULL); - - if (!thread->handle) { - goto fail; - } - - if (priority >= 99) { - SetThreadPriority(thread->handle, THREAD_PRIORITY_TIME_CRITICAL); - } else if (priority >= 50) { - SetThreadPriority(thread->handle, THREAD_PRIORITY_ABOVE_NORMAL); - } else if (priority >= 10) { - SetThreadPriority(thread->handle, THREAD_PRIORITY_NORMAL); - } else if (priority >= 1) { - SetThreadPriority(thread->handle, THREAD_PRIORITY_LOWEST); - } - - if (flags & KS_THREAD_FLAG_DETACHED) { - CloseHandle(thread->handle); - } - - status = KS_STATUS_SUCCESS; - goto done; -#else - - if (pthread_attr_init(&thread->attribute) != 0) - goto fail; - - if ((flags & KS_THREAD_FLAG_DETACHED) && pthread_attr_setdetachstate(&thread->attribute, PTHREAD_CREATE_DETACHED) != 0) - goto failpthread; - - if (thread->stack_size && pthread_attr_setstacksize(&thread->attribute, thread->stack_size) != 0) - goto failpthread; - - if (pthread_create(&thread->handle, &thread->attribute, thread_launch, thread) != 0) - goto failpthread; - - status = KS_STATUS_SUCCESS; - goto done; - - failpthread: - thread->state = KS_THREAD_FAIL; - pthread_attr_destroy(&thread->attribute); -#endif - - fail: - if (thread) { - thread->state = KS_THREAD_FAIL; - ks_pool_free(&thread); - } - done: - if (status == KS_STATUS_SUCCESS) { - while(thread->state < KS_THREAD_RUNNING && --sanity > 0) { - ks_sleep(1000); - } - - if (!sanity) { - status = KS_STATUS_FAIL; - goto fail; - } - - *rthread = thread; - ks_pool_set_cleanup(thread, NULL, ks_thread_cleanup); - } - - return status; -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/ks_thread_pool.c b/libs/libks/src/ks_thread_pool.c deleted file mode 100644 index e647e3d379..0000000000 --- a/libs/libks/src/ks_thread_pool.c +++ /dev/null @@ -1,259 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - -#define TP_MAX_QLEN 1024 - -typedef enum { - TP_STATE_DOWN = 0, - TP_STATE_RUNNING = 1 -} ks_thread_pool_state_t; - -struct ks_thread_pool_s { - uint32_t min; - uint32_t max; - uint32_t idle_sec; - size_t stack_size; - ks_thread_priority_t priority; - ks_q_t *q; - uint32_t thread_count; - uint32_t busy_thread_count; - uint32_t running_thread_count; - uint32_t dying_thread_count; - ks_thread_pool_state_t state; - ks_mutex_t *mutex; -}; - -typedef struct ks_thread_job_s { - ks_thread_function_t func; - void *data; -} ks_thread_job_t; - - -static void *worker_thread(ks_thread_t *thread, void *data); - -static int check_queue(ks_thread_pool_t *tp, ks_bool_t adding) -{ - ks_thread_t *thread; - int need = 0; - - ks_mutex_lock(tp->mutex); - - if (tp->state != TP_STATE_RUNNING) { - ks_mutex_unlock(tp->mutex); - return 1; - } - - - if (tp->thread_count < tp->min) { - need = tp->min - tp->thread_count; - } - - - if (adding) { - if (!need && tp->busy_thread_count >= tp->running_thread_count - tp->dying_thread_count && - (tp->thread_count - tp->dying_thread_count + 1 <= tp->max)) { - need = 1; - } - } - - tp->thread_count += need; - - ks_mutex_unlock(tp->mutex); - - while(need > 0) { - if (ks_thread_create_ex(&thread, worker_thread, tp, KS_THREAD_FLAG_DETACHED, tp->stack_size, tp->priority, ks_pool_get(tp)) != KS_STATUS_SUCCESS) { - ks_mutex_lock(tp->mutex); - tp->thread_count--; - ks_mutex_unlock(tp->mutex); - } - - need--; - } - /* - ks_log(KS_LOG_DEBUG, "WORKER check: adding %d need %d running %d dying %d total %d max %d\n", - adding, need, tp->running_thread_count, tp->dying_thread_count, tp->thread_count, tp->max); - */ - return need; -} - -static uint32_t TID = 0; - -static void *worker_thread(ks_thread_t *thread, void *data) -{ - ks_thread_pool_t *tp = (ks_thread_pool_t *) data; - uint32_t idle_sec = 0; - uint32_t my_id = 0; - int die = 0; - - ks_mutex_lock(tp->mutex); - tp->running_thread_count++; - my_id = ++TID; - ks_mutex_unlock(tp->mutex); - - while(tp->state == TP_STATE_RUNNING) { - ks_thread_job_t *job; - void *pop = NULL; - ks_status_t status; - - status = ks_q_pop_timeout(tp->q, &pop, 100); - if (status == KS_STATUS_BREAK) { - if (tp->state != TP_STATE_RUNNING) { - break; - } - continue; - } - - /* - ks_log(KS_LOG_DEBUG, "WORKER %d idle_sec %d running %d dying %d total %d max %d\n", - my_id, idle_sec, tp->running_thread_count, tp->dying_thread_count, tp->thread_count, tp->max); - */ - check_queue(tp, KS_FALSE); - - if (status == KS_STATUS_TIMEOUT) { // || status == KS_STATUS_BREAK) { - idle_sec++; - - if (idle_sec >= tp->idle_sec) { - - ks_mutex_lock(tp->mutex); - if (tp->running_thread_count - tp->dying_thread_count - tp->busy_thread_count > tp->min) { - tp->dying_thread_count++; - die = 1; - } - ks_mutex_unlock(tp->mutex); - - if (die) { - break; - } - } - - continue; - } - - if ((status != KS_STATUS_SUCCESS && status != KS_STATUS_BREAK)) { - ks_log(KS_LOG_ERROR, "WORKER %d POP FAIL %d %p\n", my_id, status, (void *)pop); - break; - } - - job = (ks_thread_job_t *) pop; - - ks_mutex_lock(tp->mutex); - tp->busy_thread_count++; - ks_mutex_unlock(tp->mutex); - - idle_sec = 0; - job->func(thread, job->data); - - ks_pool_free(&job); - - ks_mutex_lock(tp->mutex); - tp->busy_thread_count--; - ks_mutex_unlock(tp->mutex); - } - - ks_mutex_lock(tp->mutex); - tp->running_thread_count--; - tp->thread_count--; - if (die) { - tp->dying_thread_count--; - } - ks_mutex_unlock(tp->mutex); - - return NULL; -} - -KS_DECLARE(ks_status_t) ks_thread_pool_create(ks_thread_pool_t **tp, uint32_t min, uint32_t max, size_t stack_size, - ks_thread_priority_t priority, uint32_t idle_sec) -{ - ks_pool_t *pool = NULL; - - ks_pool_open(&pool); - - *tp = (ks_thread_pool_t *) ks_pool_alloc(pool, sizeof(ks_thread_pool_t)); - - (*tp)->min = min; - (*tp)->max = max; - (*tp)->stack_size = stack_size; - (*tp)->priority = priority; - (*tp)->state = TP_STATE_RUNNING; - (*tp)->idle_sec = idle_sec; - - ks_mutex_create(&(*tp)->mutex, KS_MUTEX_FLAG_DEFAULT, pool); - ks_q_create(&(*tp)->q, pool, TP_MAX_QLEN); - - check_queue(*tp, KS_FALSE); - - return KS_STATUS_SUCCESS; - -} - - -KS_DECLARE(ks_status_t) ks_thread_pool_destroy(ks_thread_pool_t **tp) -{ - ks_pool_t *pool = NULL; - - ks_assert(tp); - - (*tp)->state = TP_STATE_DOWN; - - while((*tp)->thread_count) { - ks_sleep(100000); - } - - pool = ks_pool_get(*tp); - ks_pool_close(&pool); - - return KS_STATUS_SUCCESS; -} - - -KS_DECLARE(ks_status_t) ks_thread_pool_add_job(ks_thread_pool_t *tp, ks_thread_function_t func, void *data) -{ - ks_thread_job_t *job = (ks_thread_job_t *) ks_pool_alloc(ks_pool_get(tp), sizeof(*job)); - - job->func = func; - job->data = data; - ks_q_push(tp->q, job); - - check_queue(tp, KS_TRUE); - - return KS_STATUS_SUCCESS; -} - - - -KS_DECLARE(ks_size_t) ks_thread_pool_backlog(ks_thread_pool_t *tp) -{ - return ks_q_size(tp->q); -} diff --git a/libs/libks/src/ks_time.c b/libs/libks/src/ks_time.c deleted file mode 100644 index 3ce8cf1a08..0000000000 --- a/libs/libks/src/ks_time.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 - -#ifdef WIN32 -#include - -static CRITICAL_SECTION timer_section; -static ks_time_t win32_tick_time_since_start = -1; -static DWORD win32_last_get_time_tick = 0; - -static uint8_t win32_use_qpc = 0; -static uint64_t win32_qpc_freq = 0; - -static inline void win32_init_timers(void) -{ - OSVERSIONINFOEX version_info; /* Used to fetch current OS version from Windows */ - InitializeCriticalSection(&timer_section); - EnterCriticalSection(&timer_section); - - ZeroMemory(&version_info, sizeof(OSVERSIONINFOEX)); - version_info.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); - - /* Check if we should use timeGetTime() (pre-Vista) or QueryPerformanceCounter() (Vista and later) */ - - //if (GetVersionEx((OSVERSIONINFO*) &version_info)) { - if (IsWindowsVistaOrGreater()) { - //if (version_info.dwPlatformId == VER_PLATFORM_WIN32_NT && version_info.dwMajorVersion >= 6) { - if (QueryPerformanceFrequency((LARGE_INTEGER*)&win32_qpc_freq) && win32_qpc_freq > 0) { - /* At least Vista, and QueryPerformanceFrequency() suceeded, enable qpc */ - win32_use_qpc = 1; - } else { - /* At least Vista, but QueryPerformanceFrequency() failed, disable qpc */ - win32_use_qpc = 0; - } - //} else { - /* Older then Vista, disable qpc */ - //win32_use_qpc = 0; - //} - } else { - /* Unknown version - we want at least Vista, disable qpc */ - win32_use_qpc = 0; - } - - if (win32_use_qpc) { - uint64_t count = 0; - - if (!QueryPerformanceCounter((LARGE_INTEGER*)&count) || count == 0) { - /* Call to QueryPerformanceCounter() failed, disable qpc again */ - win32_use_qpc = 0; - } - } - - if (!win32_use_qpc) { - /* This will enable timeGetTime() instead, qpc init failed */ - win32_last_get_time_tick = timeGetTime(); - win32_tick_time_since_start = win32_last_get_time_tick; - } - - LeaveCriticalSection(&timer_section); -} - -KS_DECLARE(ks_time_t) ks_time_now(void) -{ - ks_time_t now; - - if (win32_use_qpc) { - /* Use QueryPerformanceCounter */ - uint64_t count = 0; - QueryPerformanceCounter((LARGE_INTEGER*)&count); - now = ((count * 1000000) / win32_qpc_freq); - } else { - /* Use good old timeGetTime() */ - DWORD tick_now; - DWORD tick_diff; - - tick_now = timeGetTime(); - if (win32_tick_time_since_start != -1) { - EnterCriticalSection(&timer_section); - /* just add diff (to make it work more than 50 days). */ - tick_diff = tick_now - win32_last_get_time_tick; - win32_tick_time_since_start += tick_diff; - - win32_last_get_time_tick = tick_now; - now = (win32_tick_time_since_start * 1000); - LeaveCriticalSection(&timer_section); - } else { - /* If someone is calling us before timer is initialized, - * return the current tick - */ - now = (tick_now * 1000); - } - } - - return now; -} - -KS_DECLARE(ks_time_t) ks_time_now_sec(void) -{ - ks_time_t now; - - if (win32_use_qpc) { - /* Use QueryPerformanceCounter */ - uint64_t count = 0; - QueryPerformanceCounter((LARGE_INTEGER*)&count); - now = (count / win32_qpc_freq); - } else { - /* Use good old timeGetTime() */ - DWORD tick_now; - DWORD tick_diff; - - tick_now = timeGetTime(); - if (win32_tick_time_since_start != -1) { - EnterCriticalSection(&timer_section); - /* just add diff (to make it work more than 50 days). */ - tick_diff = tick_now - win32_last_get_time_tick; - win32_tick_time_since_start += tick_diff; - - win32_last_get_time_tick = tick_now; - now = (win32_tick_time_since_start / 1000); - LeaveCriticalSection(&timer_section); - } else { - /* If someone is calling us before timer is initialized, - * return the current tick - */ - now = (tick_now / 1000); - } - } - - return now; -} - -KS_DECLARE(void) ks_sleep(ks_time_t microsec) -{ - - LARGE_INTEGER perfCnt, start, now; - - QueryPerformanceFrequency(&perfCnt); - QueryPerformanceCounter(&start); - - do { - QueryPerformanceCounter((LARGE_INTEGER*) &now); - if (!SwitchToThread()) Sleep(1); - } while ((now.QuadPart - start.QuadPart) / (float)(perfCnt.QuadPart) * 1000 * 1000 < (DWORD)microsec); - -} - -#else //!WINDOWS, UNIX ETC -KS_DECLARE(ks_time_t) ks_time_now(void) -{ - ks_time_t now; - -#if (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)) - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - now = (int64_t)ts.tv_sec * 1000000 + ((int64_t)ts.tv_nsec / 1000); -#else - struct timeval tv; - gettimeofday(&tv, NULL); - now = tv.tv_sec * 1000000 + tv.tv_usec; -#endif - - return now; -} - -KS_DECLARE(ks_time_t) ks_time_now_sec(void) -{ - ks_time_t now; - -#if (defined(HAVE_CLOCK_GETTIME) && defined(CLOCK_REALTIME)) - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - now = (int64_t)ts.tv_sec; -#else - struct timeval tv; - gettimeofday(&tv, NULL); - now = tv.tv_sec; -#endif - - return now; -} - -#if !defined(HAVE_CLOCK_NANOSLEEP) && !defined(__APPLE__) -static void generic_sleep(ks_time_t microsec) -{ -#ifdef HAVE_USLEEP - usleep(microsec); -#else - struct timeval tv; - tv.tv_usec = ks_time_usec(microsec); - tv.tv_sec = ks_time_sec(microsec); - select(0, NULL, NULL, NULL, &tv); -#endif -} -#endif - -KS_DECLARE(void) ks_sleep(ks_time_t microsec) -{ -#if defined(HAVE_CLOCK_NANOSLEEP) || defined(__APPLE__) - struct timespec ts; -#endif - -#if defined(HAVE_CLOCK_NANOSLEEP) - ts.tv_sec = ks_time_sec(microsec); - ts.tv_nsec = ks_time_nsec(microsec); - clock_nanosleep(CLOCK_MONOTONIC, 0, &ts, NULL); -#elif defined(__APPLE__) - ts.tv_sec = ks_time_sec(microsec); - ts.tv_nsec = ks_time_usec(microsec) * 900; - nanosleep(&ts, NULL); -#else - generic_sleep(microsec); -#endif - -#if defined(__APPLE__) - sched_yield(); -#endif - -} - -#endif - -KS_DECLARE(void) ks_time_init(void) -{ -#ifdef _WINDOWS_ - win32_init_timers(); -#endif -} - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/src/kws.c b/libs/libks/src/kws.c deleted file mode 100644 index a88275cf9e..0000000000 --- a/libs/libks/src/kws.c +++ /dev/null @@ -1,1263 +0,0 @@ -/* - * Copyright (c) 2007-2014, Anthony Minessale II - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * - * * Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * * 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. - * - * * Neither the name of the original author; nor the names of any 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 "ks.h" - - -#ifdef _MSC_VER -/* warning C4706: assignment within conditional expression*/ -#pragma warning(disable: 4706) -#endif - -#define WS_BLOCK 1 -#define WS_NOBLOCK 0 - -#define WS_INIT_SANITY 5000 -#define WS_WRITE_SANITY 2000 - -#define SHA1_HASH_SIZE 20 - -static const char c64[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - -//static ks_ssize_t ws_send_buf(kws_t *kws, kws_opcode_t oc); -//static ks_ssize_t ws_feed_buf(kws_t *kws, void *data, ks_size_t bytes); - - -struct kws_s { - ks_socket_t sock; - kws_type_t type; - char *buffer; - char *bbuffer; - char *body; - char *uri; - ks_size_t buflen; - ks_size_t bbuflen; - ks_ssize_t datalen; - ks_ssize_t wdatalen; - char *payload; - ks_ssize_t plen; - ks_ssize_t rplen; - ks_ssize_t packetlen; - SSL *ssl; - int handshake; - uint8_t down; - int secure; - uint8_t close_sock; - SSL_CTX *ssl_ctx; - int block; - int sanity; - int secure_established; - int logical_established; - int stay_open; - int x; - void *write_buffer; - ks_size_t write_buffer_len; - char *req_uri; - char *req_host; - char *req_proto; - - char **sans; - ks_size_t sans_count; -}; - - - -static int cheezy_get_var(char *data, char *name, char *buf, ks_size_t buflen) -{ - char *p=data; - - /* the old way didnt make sure that variable values were used for the name hunt - * and didnt ensure that only a full match of the variable name was used - */ - ks_assert(buflen > 0); - - do { - if(!strncmp(p,name,strlen(name)) && *(p+strlen(name))==':') break; - } while((p = (strstr(p,"\n")+1))!=(char *)1); - - - if (p && p != (char *)1 && *p!='\0') { - char *v, *e = 0; - - v = strchr(p, ':'); - if (v) { - v++; - while(v && *v == ' ') { - v++; - } - if (v) { - e = strchr(v, '\r'); - if (!e) { - e = strchr(v, '\n'); - } - } - - if (v && e) { - size_t cplen; - ks_size_t len = e - v; - - if (len > buflen - 1) { - cplen = buflen - 1; - } else { - cplen = len; - } - - strncpy(buf, v, cplen); - *(buf+cplen) = '\0'; - return 1; - } - - } - } - return 0; -} - -static int b64encode(unsigned char *in, ks_size_t ilen, unsigned char *out, ks_size_t olen) -{ - int y=0,bytes=0; - ks_size_t x=0; - unsigned int b=0,l=0; - - if(olen) { - } - - for(x=0;x= 6) { - out[bytes++] = c64[(b>>(l-=6))%64]; - if(++y!=72) { - continue; - } - //out[bytes++] = '\n'; - y=0; - } - } - - if (l > 0) { - out[bytes++] = c64[((b%16)<<(6-l))%64]; - } - if (l != 0) while (l < 6) { - out[bytes++] = '=', l += 2; - } - - return 0; -} - -static void sha1_digest(unsigned char *digest, char *in) -{ - SHA_CTX sha; - - SHA1_Init(&sha); - SHA1_Update(&sha, in, strlen(in)); - SHA1_Final(digest, &sha); - -} - -/* fix me when we get real rand funcs in ks */ -static void gen_nonce(unsigned char *buf, uint16_t len) -{ - int max = 255; - uint16_t x; - ks_time_t time_now = ks_time_now(); - srand((unsigned int)(((time_now >> 32) ^ time_now) & 0xffffffff)); - - for (x = 0; x < len; x++) { - int j = (int) (max * 1.0 * rand() / (RAND_MAX + 1.0)); - buf[x] = (char) j; - } -} - -static int verify_accept(kws_t *kws, const unsigned char *enonce, const char *accept) -{ - char input[256] = ""; - unsigned char output[SHA1_HASH_SIZE] = ""; - char b64[256] = ""; - - snprintf(input, sizeof(input), "%s%s", enonce, WEBSOCKET_GUID); - sha1_digest(output, input); - b64encode((unsigned char *)output, SHA1_HASH_SIZE, (unsigned char *)b64, sizeof(b64)); - - return !strcmp(b64, accept); -} - -static int ws_client_handshake(kws_t *kws) -{ - unsigned char nonce[16]; - unsigned char enonce[128] = ""; - char req[256] = ""; - - gen_nonce(nonce, sizeof(nonce)); - b64encode(nonce, sizeof(nonce), enonce, sizeof(enonce)); - - ks_snprintf(req, sizeof(req), - "GET %s HTTP/1.1\r\n" - "Host: %s\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Key: %s\r\n" - "Sec-WebSocket-Protocol: %s\r\n" - "Sec-WebSocket-Version: 13\r\n" - "\r\n", - kws->req_uri, kws->req_host, enonce, kws->req_proto); - - kws_raw_write(kws, req, strlen(req)); - - ks_ssize_t bytes; - - do { - bytes = kws_raw_read(kws, kws->buffer + kws->datalen, kws->buflen - kws->datalen, WS_BLOCK); - } while (bytes > 0 && !strstr((char *)kws->buffer, "\r\n\r\n")); - - if (bytes > 0) { - char accept[128] = ""; - - cheezy_get_var(kws->buffer, "Sec-WebSocket-Accept", accept, sizeof(accept)); - - if (zstr_buf(accept) || !verify_accept(kws, enonce, (char *)accept)) { - return -1; - } - } else { - return -1; - } - - kws->handshake = 1; - - return 0; -} - -static int ws_server_handshake(kws_t *kws) -{ - char key[256] = ""; - char version[5] = ""; - char proto[256] = ""; - char proto_buf[384] = ""; - char input[256] = ""; - unsigned char output[SHA1_HASH_SIZE] = ""; - char b64[256] = ""; - char respond[512] = ""; - ks_ssize_t bytes; - char *p, *e = 0; - - if (kws->sock == KS_SOCK_INVALID) { - return -3; - } - - while((bytes = kws_raw_read(kws, kws->buffer + kws->datalen, kws->buflen - kws->datalen, WS_BLOCK)) > 0) { - kws->datalen += bytes; - if (strstr(kws->buffer, "\r\n\r\n") || strstr(kws->buffer, "\n\n")) { - break; - } - } - - if (bytes < 0 || ((ks_size_t)bytes) > kws->buflen - 1) { - goto err; - } - - *(kws->buffer + kws->datalen) = '\0'; - - if (strncasecmp(kws->buffer, "GET ", 4)) { - goto err; - } - - p = kws->buffer + 4; - - e = strchr(p, ' '); - if (!e) { - goto err; - } - - kws->uri = ks_pool_alloc(ks_pool_get(kws), (unsigned long)(e-p) + 1); - strncpy(kws->uri, p, e-p); - *(kws->uri + (e-p)) = '\0'; - - cheezy_get_var(kws->buffer, "Sec-WebSocket-Key", key, sizeof(key)); - cheezy_get_var(kws->buffer, "Sec-WebSocket-Version", version, sizeof(version)); - cheezy_get_var(kws->buffer, "Sec-WebSocket-Protocol", proto, sizeof(proto)); - - if (!*key) { - goto err; - } - - snprintf(input, sizeof(input), "%s%s", key, WEBSOCKET_GUID); - sha1_digest(output, input); - b64encode((unsigned char *)output, SHA1_HASH_SIZE, (unsigned char *)b64, sizeof(b64)); - - if (*proto) { - snprintf(proto_buf, sizeof(proto_buf), "Sec-WebSocket-Protocol: %s\r\n", proto); - } - - snprintf(respond, sizeof(respond), - "HTTP/1.1 101 Switching Protocols\r\n" - "Upgrade: websocket\r\n" - "Connection: Upgrade\r\n" - "Sec-WebSocket-Accept: %s\r\n" - "%s\r\n", - b64, - proto_buf); - respond[511] = 0; - - if (kws_raw_write(kws, respond, strlen(respond)) != (ks_ssize_t)strlen(respond)) { - goto err; - } - - kws->handshake = 1; - - return 0; - - err: - - if (!kws->stay_open) { - - if (bytes > 0) { - snprintf(respond, sizeof(respond), "HTTP/1.1 400 Bad Request\r\n" - "Sec-WebSocket-Version: 13\r\n\r\n"); - respond[511] = 0; - - kws_raw_write(kws, respond, strlen(respond)); - } - - kws_close(kws, WS_NONE); - } - - return -1; - -} - -KS_DECLARE(ks_ssize_t) kws_raw_read(kws_t *kws, void *data, ks_size_t bytes, int block) -{ - int r; - int err = 0; - - kws->x++; - if (kws->x > 250) ks_sleep_ms(1); - - if (kws->ssl) { - do { - r = SSL_read(kws->ssl, data, (int)bytes); - - if (r == -1) { - err = SSL_get_error(kws->ssl, r); - - if (err == SSL_ERROR_WANT_READ) { - if (!block) { - r = -2; - goto end; - } - kws->x++; - ks_sleep_ms(10); - } else { - r = -1; - goto end; - } - } - - } while (r == -1 && err == SSL_ERROR_WANT_READ && kws->x < 1000); - - goto end; - } - - do { - - r = recv(kws->sock, data, (int)bytes, 0); - - if (r == -1) { - if (!block && ks_errno_is_blocking(ks_errno())) { - r = -2; - goto end; - } - - if (block) { - kws->x++; - ks_sleep_ms(10); - } - } - } while (r == -1 && ks_errno_is_blocking(ks_errno()) && kws->x < 1000); - - end: - - if (kws->x >= 10000 || (block && kws->x >= 1000)) { - r = -1; - } - - if (r > 0) { - *((char *)data + r) = '\0'; - } - - if (r >= 0) { - kws->x = 0; - } - - return r; -} - -KS_DECLARE(ks_ssize_t) kws_raw_write(kws_t *kws, void *data, ks_size_t bytes) -{ - int r; - int sanity = WS_WRITE_SANITY; - int ssl_err = 0; - ks_size_t wrote = 0; - - if (kws->ssl) { - do { - r = SSL_write(kws->ssl, (void *)((unsigned char *)data + wrote), (int)(bytes - wrote)); - - if (r > 0) { - wrote += r; - } - - if (sanity < WS_WRITE_SANITY) { - int ms = 1; - - if (kws->block) { - if (sanity < WS_WRITE_SANITY * 3 / 4) { - ms = 60; - } else if (sanity < WS_WRITE_SANITY / 2) { - ms = 10; - } - } - ks_sleep_ms(ms); - } - - if (r == -1) { - if ((ssl_err = SSL_get_error(kws->ssl, r)) != SSL_ERROR_WANT_WRITE) { - break; - } - ssl_err = 0; - } - - } while (--sanity > 0 && kws->block && wrote < bytes); - - if (ssl_err) { - r = ssl_err * -1; - } - - return r; - } - - do { - r = send(kws->sock, (void *)((unsigned char *)data + wrote), (int)(bytes - wrote), 0); - - if (r > 0) { - wrote += r; - } - - if (sanity < WS_WRITE_SANITY) { - int ms = 1; - - if (kws->block) { - if (sanity < WS_WRITE_SANITY * 3 / 4) { - ms = 60; - } else if (sanity < WS_WRITE_SANITY / 2) { - ms = 10; - } - } - ks_sleep_ms(ms); - } - - if (r == -1) { - if (!ks_errno_is_blocking(ks_errno())) { - break; - } - } - - } while (--sanity > 0 && kws->block && wrote < bytes); - - //if (r<0) { - //printf("wRITE FAIL: %s\n", strerror(errno)); - //} - - return r; -} - -static void setup_socket(ks_socket_t sock) -{ - ks_socket_option(sock, KS_SO_NONBLOCK, KS_TRUE); -} - -static void restore_socket(ks_socket_t sock) -{ - ks_socket_option(sock, KS_SO_NONBLOCK, KS_FALSE); -} - -static int establish_client_logical_layer(kws_t *kws) -{ - - if (!kws->sanity) { - return -1; - } - - if (kws->logical_established) { - return 0; - } - - if (kws->secure && !kws->secure_established) { - int code; - - if (!kws->ssl) { - kws->ssl = SSL_new(kws->ssl_ctx); - assert(kws->ssl); - - SSL_set_fd(kws->ssl, (int)kws->sock); - } - - do { - code = SSL_connect(kws->ssl); - - if (code == 1) { - kws->secure_established = 1; - break; - } - - if (code == 0) { - return -1; - } - - if (code < 0) { - int serr = SSL_get_error(kws->ssl, code); - if (code == -1 && serr != SSL_ERROR_WANT_READ) { - return -1; - } - } - - if (kws->block) { - ks_sleep_ms(10); - } else { - ks_sleep_ms(1); - } - - kws->sanity--; - - if (!kws->block) { - return -2; - } - - } while (kws->sanity > 0); - - if (!kws->sanity) { - return -1; - } - } - - while (!kws->down && !kws->handshake) { - int r = ws_client_handshake(kws); - - if (r < 0) { - kws->down = 1; - return -1; - } - - if (!kws->handshake && !kws->block) { - return -2; - } - - } - - kws->logical_established = 1; - - return 0; -} - -static int establish_server_logical_layer(kws_t *kws) -{ - - if (!kws->sanity) { - return -1; - } - - if (kws->logical_established) { - return 0; - } - - if (kws->secure && !kws->secure_established) { - int code; - - if (!kws->ssl) { - kws->ssl = SSL_new(kws->ssl_ctx); - assert(kws->ssl); - - SSL_set_fd(kws->ssl, (int)kws->sock); - } - - do { - code = SSL_accept(kws->ssl); - - if (code == 1) { - kws->secure_established = 1; - break; - } - - if (code == 0) { - return -1; - } - - if (code < 0) { - int sslerr = SSL_get_error(kws->ssl, code); - if (code == -1 && sslerr != SSL_ERROR_WANT_READ) { - return -1; - } - } - - if (kws->block) { - ks_sleep_ms(10); - } else { - ks_sleep_ms(1); - } - - kws->sanity--; - - if (!kws->block) { - return -2; - } - - } while (kws->sanity > 0); - - if (!kws->sanity) { - return -1; - } - - } - - while (!kws->down && !kws->handshake) { - int r = ws_server_handshake(kws); - - if (r < 0) { - kws->down = 1; - return -1; - } - - if (!kws->handshake && !kws->block) { - return -2; - } - - } - - kws->logical_established = 1; - - return 0; -} - -static int establish_logical_layer(kws_t *kws) -{ - if (kws->type == KWS_CLIENT) { - return establish_client_logical_layer(kws); - } else { - return establish_server_logical_layer(kws); - } -} - -KS_DECLARE(ks_status_t) kws_init(kws_t **kwsP, ks_socket_t sock, SSL_CTX *ssl_ctx, const char *client_data, kws_flag_t flags, ks_pool_t *pool) -{ - kws_t *kws; - - kws = ks_pool_alloc(pool, sizeof(*kws)); - - if ((flags & KWS_CLOSE_SOCK)) { - kws->close_sock = 1; - } - - if ((flags & KWS_STAY_OPEN)) { - kws->stay_open = 1; - } - - if ((flags & KWS_BLOCK)) { - kws->block = 1; - } - - if (client_data) { - char *p = NULL; - kws->req_uri = ks_pstrdup(pool, client_data); - - if ((p = strchr(kws->req_uri, ':'))) { - *p++ = '\0'; - kws->req_host = p; - if ((p = strchr(kws->req_host, ':'))) { - *p++ = '\0'; - kws->req_proto = p; - } - } - - kws->type = KWS_CLIENT; - } else { - kws->type = KWS_SERVER; - } - - kws->sock = sock; - kws->sanity = WS_INIT_SANITY; - kws->ssl_ctx = ssl_ctx; - - kws->buflen = 1024 * 64; - kws->bbuflen = kws->buflen; - - kws->buffer = ks_pool_alloc(pool, (unsigned long)kws->buflen); - kws->bbuffer = ks_pool_alloc(pool, (unsigned long)kws->bbuflen); - //printf("init %p %ld\n", (void *) kws->bbuffer, kws->bbuflen); - //memset(kws->buffer, 0, kws->buflen); - //memset(kws->bbuffer, 0, kws->bbuflen); - - kws->secure = ssl_ctx ? 1 : 0; - - setup_socket(sock); - - if (establish_logical_layer(kws) == -1) { - goto err; - } - - if (kws->down) { - goto err; - } - - if (kws->type == KWS_SERVER) - { - X509 *cert = SSL_get_peer_certificate(kws->ssl); - - if (cert && SSL_get_verify_result(kws->ssl) == X509_V_OK) { - GENERAL_NAMES *sans = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - if (sans) { - kws->sans_count = (ks_size_t)sk_GENERAL_NAME_num(sans); - if (kws->sans_count) kws->sans = ks_pool_calloc(pool, kws->sans_count, sizeof(char *)); - for (ks_size_t i = 0; i < kws->sans_count; i++) { - const GENERAL_NAME *gname = sk_GENERAL_NAME_value(sans, (int)i); - char *name = (char *)ASN1_STRING_data(gname->d.dNSName); - kws->sans[i] = ks_pstrdup(pool, name); - } - sk_GENERAL_NAME_pop_free(sans, GENERAL_NAME_free); - } - } - - if (cert) X509_free(cert); - } - - *kwsP = kws; - - return KS_STATUS_SUCCESS; - - err: - kws_destroy(&kws); - - return KS_STATUS_FAIL; -} - -KS_DECLARE(void) kws_destroy(kws_t **kwsP) -{ - kws_t *kws; - ks_assert(kwsP); - - if (!(kws = *kwsP)) { - return; - } - - *kwsP = NULL; - - if (!kws->down) { - kws_close(kws, WS_NONE); - } - - if (kws->down > 1) { - return; - } - - kws->down = 2; - - if (kws->write_buffer) { - ks_pool_free(&kws->write_buffer); - kws->write_buffer = NULL; - kws->write_buffer_len = 0; - } - - if (kws->ssl) { - int code; - do { - code = SSL_shutdown(kws->ssl); - } while (code == -1 && SSL_get_error(kws->ssl, code) == SSL_ERROR_WANT_READ); - - SSL_free(kws->ssl); - kws->ssl = NULL; - } - - if (kws->buffer) ks_pool_free(&kws->buffer); - if (kws->bbuffer) ks_pool_free(&kws->bbuffer); - - kws->buffer = kws->bbuffer = NULL; - - ks_pool_free(&kws); - kws = NULL; -} - -KS_DECLARE(ks_ssize_t) kws_close(kws_t *kws, int16_t reason) -{ - - if (kws->down) { - return -1; - } - - kws->down = 1; - - if (kws->uri) { - ks_pool_free(&kws->uri); - kws->uri = NULL; - } - - if (reason && kws->sock != KS_SOCK_INVALID) { - uint16_t *u16; - uint8_t fr[4] = {WSOC_CLOSE | 0x80, 2, 0}; - - u16 = (uint16_t *) &fr[2]; - *u16 = htons((int16_t)reason); - kws_raw_write(kws, fr, 4); - } - - restore_socket(kws->sock); - - if (kws->close_sock && kws->sock != KS_SOCK_INVALID) { -#ifndef WIN32 - close(kws->sock); -#else - closesocket(kws->sock); -#endif - } - - kws->sock = KS_SOCK_INVALID; - - return reason * -1; - -} - -#ifndef WIN32 -#if defined(HAVE_BYTESWAP_H) -#include -#elif defined(HAVE_SYS_ENDIAN_H) -#include -#elif defined (__APPLE__) -#include -#define bswap_16 OSSwapInt16 -#define bswap_32 OSSwapInt32 -#define bswap_64 OSSwapInt64 -#elif defined (__UCLIBC__) -#else -#define bswap_16(value) ((((value) & 0xff) << 8) | ((value) >> 8)) -#define bswap_32(value) (((uint32_t)bswap_16((uint16_t)((value) & 0xffff)) << 16) | (uint32_t)bswap_16((uint16_t)((value) >> 16))) -#define bswap_64(value) (((uint64_t)bswap_32((uint32_t)((value) & 0xffffffff)) << 32) | (uint64_t)bswap_32((uint32_t)((value) >> 32))) -#endif -#endif - -uint64_t hton64(uint64_t val) -{ -#if __BYTE_ORDER == __BIG_ENDIAN - return (val); -#else - return bswap_64(val); -#endif -} - -uint64_t ntoh64(uint64_t val) -{ -#if __BYTE_ORDER == __BIG_ENDIAN - return (val); -#else - return bswap_64(val); -#endif -} - -KS_DECLARE(ks_status_t) kws_peer_sans(kws_t *kws, char *buf, ks_size_t buflen) -{ - ks_status_t ret = KS_STATUS_SUCCESS; - X509 *cert = NULL; - - ks_assert(kws); - ks_assert(buf); - ks_assert(buflen); - - cert = SSL_get_peer_certificate(kws->ssl); - if (!cert) { - ret = KS_STATUS_FAIL; - goto done; - } - - if (SSL_get_verify_result(kws->ssl) != X509_V_OK) { - ret = KS_STATUS_FAIL; - goto done; - } - - //if (X509_NAME_get_text_by_NID(X509_get_subject_name(cert), NID_commonName, buf, (int)buflen) < 0) { - // ret = KS_STATUS_FAIL; - // goto done; - //} - - GENERAL_NAMES *san_names = X509_get_ext_d2i(cert, NID_subject_alt_name, NULL, NULL); - if (san_names) { - int san_names_nb = sk_GENERAL_NAME_num(san_names); - for (int i = 0; i < san_names_nb; i++) { - const GENERAL_NAME *current_name = sk_GENERAL_NAME_value(san_names, i); - char *name = (char *)ASN1_STRING_data(current_name->d.dNSName); - if (name) continue; - } - sk_GENERAL_NAME_pop_free(san_names, GENERAL_NAME_free); - } -done: - if (cert) X509_free(cert); - - return ret; -} - -KS_DECLARE(ks_ssize_t) kws_read_frame(kws_t *kws, kws_opcode_t *oc, uint8_t **data) -{ - - ks_ssize_t need = 2; - char *maskp; - int ll = 0; - int frag = 0; - int blen; - - kws->body = kws->bbuffer; - kws->packetlen = 0; - - again: - need = 2; - maskp = NULL; - *data = NULL; - - ll = establish_logical_layer(kws); - - if (ll < 0) { - return ll; - } - - if (kws->down) { - return -1; - } - - if (!kws->handshake) { - return kws_close(kws, WS_NONE); - } - - if ((kws->datalen = kws_raw_read(kws, kws->buffer, 9, kws->block)) < 0) { - if (kws->datalen == -2) { - return -2; - } - return kws_close(kws, WS_NONE); - } - - if (kws->datalen < need) { - ssize_t bytes = kws_raw_read(kws, kws->buffer + kws->datalen, 9 - kws->datalen, WS_BLOCK); - - if (bytes < 0 || (kws->datalen += bytes) < need) { - /* too small - protocol err */ - return kws_close(kws, WS_NONE); - } - } - - *oc = *kws->buffer & 0xf; - - switch(*oc) { - case WSOC_CLOSE: - { - kws->plen = kws->buffer[1] & 0x7f; - *data = (uint8_t *) &kws->buffer[2]; - return kws_close(kws, 1000); - } - break; - case WSOC_CONTINUATION: - case WSOC_TEXT: - case WSOC_BINARY: - case WSOC_PING: - case WSOC_PONG: - { - int fin = (kws->buffer[0] >> 7) & 1; - int mask = (kws->buffer[1] >> 7) & 1; - - - if (!fin && *oc != WSOC_CONTINUATION) { - frag = 1; - } else if (fin && *oc == WSOC_CONTINUATION) { - frag = 0; - } - - if (mask) { - need += 4; - - if (need > kws->datalen) { - /* too small - protocol err */ - *oc = WSOC_CLOSE; - return kws_close(kws, WS_NONE); - } - } - - kws->plen = kws->buffer[1] & 0x7f; - kws->payload = &kws->buffer[2]; - - if (kws->plen == 127) { - uint64_t *u64; - ks_ssize_t more = 0; - - need += 8; - - if (need > kws->datalen) { - /* too small - protocol err */ - //*oc = WSOC_CLOSE; - //return kws_close(kws, WS_PROTO_ERR); - - more = kws_raw_read(kws, kws->buffer + kws->datalen, (int)(need - kws->datalen), WS_BLOCK); - - if (more < 0 || more < need - kws->datalen) { - *oc = WSOC_CLOSE; - return kws_close(kws, WS_NONE); - } else { - kws->datalen += more; - } - - - } - - u64 = (uint64_t *) kws->payload; - kws->payload += 8; - kws->plen = (ks_ssize_t)ntoh64(*u64); - } else if (kws->plen == 126) { - uint16_t *u16; - - need += 2; - - if (need > kws->datalen) { - /* too small - protocol err */ - *oc = WSOC_CLOSE; - return kws_close(kws, WS_NONE); - } - - u16 = (uint16_t *) kws->payload; - kws->payload += 2; - kws->plen = ntohs(*u16); - } - - if (mask) { - maskp = (char *)kws->payload; - kws->payload += 4; - } - - need = (kws->plen - (kws->datalen - need)); - - if (need < 0) { - /* invalid read - protocol err .. */ - *oc = WSOC_CLOSE; - return kws_close(kws, WS_NONE); - } - - blen = (int)(kws->body - kws->bbuffer); - - if (need + blen > (ks_ssize_t)kws->bbuflen) { - void *tmp; - - kws->bbuflen = need + blen + kws->rplen; - if ((tmp = ks_pool_resize(kws->bbuffer, (unsigned long)kws->bbuflen))) { - kws->bbuffer = tmp; - } else { - abort(); - } - - kws->body = kws->bbuffer + blen; - } - - kws->rplen = kws->plen - need; - - if (kws->rplen) { - ks_assert((kws->body + kws->rplen) <= (kws->bbuffer + kws->bbuflen)); - memcpy(kws->body, kws->payload, kws->rplen); - } - - while(need) { - ks_assert((kws->body + need + kws->rplen) <= (kws->bbuffer + kws->bbuflen)); - ks_ssize_t r = kws_raw_read(kws, kws->body + kws->rplen, need, WS_BLOCK); - - if (r < 1) { - /* invalid read - protocol err .. */ - *oc = WSOC_CLOSE; - return kws_close(kws, WS_NONE); - } - - kws->datalen += r; - kws->rplen += r; - need -= r; - } - - if (mask && maskp) { - ks_ssize_t i; - - for (i = 0; i < kws->datalen; i++) { - kws->body[i] ^= maskp[i % 4]; - } - } - - - if (*oc == WSOC_PING) { - kws_write_frame(kws, WSOC_PONG, kws->body, kws->rplen); - goto again; - } - - *(kws->body+kws->rplen) = '\0'; - kws->packetlen += kws->rplen; - kws->body += kws->rplen; - - if (frag) { - goto again; - } - - *data = (uint8_t *)kws->bbuffer; - - //printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", kws->packetlen, *oc, (char *)*data); - - - return kws->packetlen; - } - break; - default: - { - /* invalid op code - protocol err .. */ - *oc = WSOC_CLOSE; - return kws_close(kws, WS_PROTO_ERR); - } - break; - } -} - -#if 0 -static ks_ssize_t ws_feed_buf(kws_t *kws, void *data, ks_size_t bytes) -{ - - if (bytes + kws->wdatalen > kws->buflen) { - return -1; - } - - memcpy(kws->wbuffer + kws->wdatalen, data, bytes); - - kws->wdatalen += bytes; - - return bytes; -} - -static ks_ssize_t ws_send_buf(kws_t *kws, kws_opcode_t oc) -{ - ks_ssize_t r = 0; - - if (!kws->wdatalen) { - return -1; - } - - r = ws_write_frame(kws, oc, kws->wbuffer, kws->wdatalen); - - kws->wdatalen = 0; - - return r; -} -#endif - -KS_DECLARE(ks_ssize_t) kws_write_frame(kws_t *kws, kws_opcode_t oc, void *data, ks_size_t bytes) -{ - uint8_t hdr[14] = { 0 }; - ks_size_t hlen = 2; - uint8_t *bp; - ks_ssize_t raw_ret = 0; - - if (kws->down) { - return -1; - } - - //printf("WRITE[%ld]-----------------------------:\n[%s]\n-----------------------------------\n", bytes, (char *) data); - - hdr[0] = (uint8_t)(oc | 0x80); - - if (bytes < 126) { - hdr[1] = (uint8_t)bytes; - } else if (bytes < 0x10000) { - uint16_t *u16; - - hdr[1] = 126; - hlen += 2; - - u16 = (uint16_t *) &hdr[2]; - *u16 = htons((uint16_t) bytes); - - } else { - uint64_t *u64; - - hdr[1] = 127; - hlen += 8; - - u64 = (uint64_t *) &hdr[2]; - *u64 = hton64(bytes); - } - - if (kws->write_buffer_len < (hlen + bytes + 1)) { - void *tmp; - - kws->write_buffer_len = hlen + bytes + 1; - if (!kws->write_buffer) kws->write_buffer = ks_pool_alloc(ks_pool_get(kws), (unsigned long)kws->write_buffer_len); - else if ((tmp = ks_pool_resize(kws->write_buffer, (unsigned long)kws->write_buffer_len))) { - kws->write_buffer = tmp; - } else { - abort(); - } - } - - bp = (uint8_t *) kws->write_buffer; - memcpy(bp, (void *) &hdr[0], hlen); - memcpy(bp + hlen, data, bytes); - - raw_ret = kws_raw_write(kws, bp, (hlen + bytes)); - - if (raw_ret != (ks_ssize_t) (hlen + bytes)) { - return raw_ret; - } - - return bytes; -} - -KS_DECLARE(ks_status_t) kws_get_buffer(kws_t *kws, char **bufP, ks_size_t *buflen) -{ - *bufP = kws->buffer; - *buflen = kws->datalen; - - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_size_t) kws_sans_count(kws_t *kws) -{ - ks_assert(kws); - - return kws->sans_count; -} - -KS_DECLARE(const char *) kws_sans_get(kws_t *kws, ks_size_t index) -{ - ks_assert(kws); - if (index >= kws->sans_count) return NULL; - return kws->sans[index]; -} diff --git a/libs/libks/src/simclist.c b/libs/libks/src/simclist.c deleted file mode 100755 index 539e2e7159..0000000000 --- a/libs/libks/src/simclist.c +++ /dev/null @@ -1,1728 +0,0 @@ -/* -* Copyright (c) 2007,2008,2009,2010,2011 Mij -* -* 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. -*/ - - -/* -* SimCList library. See http://mij.oltrelinux.com/devel/simclist -*/ - -/* SimCList implementation, version 1.6 */ -#include - -#include -#include -#include /* for setting errno */ -#include -#ifndef _WIN32 -/* not in Windows! */ -# include -# include -#endif -#ifndef SIMCLIST_NO_DUMPRESTORE -/* includes for dump/restore */ -# include -# include /* for READ_ERRCHECK() and write() */ -# include /* for open() etc */ -# ifndef _WIN32 -# include /* for htons() on UNIX */ -# else -# include /* for htons() on Windows */ -# endif -#endif - -#include - - -#include /* for open()'s access modes S_IRUSR etc */ -#include - -#if defined(_MSC_VER) || defined(__MINGW32__) -/* provide gettimeofday() missing in Windows */ -#ifdef _MSC_VER -#pragma comment(lib, "Winmm.lib") -#endif -int gettimeofday(struct timeval *tp, void *tzp) { - DWORD t; - - /* XSI says: "If tzp is not a null pointer, the behavior is unspecified" */ - ks_assert(tzp == NULL); - - t = timeGetTime(); - tp->tv_sec = t / 1000; - tp->tv_usec = t % 1000; - return 0; -} -#endif - - -/* work around lack of inttypes.h support in broken Microsoft Visual Studio compilers */ -#if !defined(_WIN32) || !defined(_MSC_VER) -# include /* (u)int*_t */ -#else -# include -typedef UINT8 uint8_t; -typedef UINT16 uint16_t; -typedef ULONG32 uint32_t; -typedef UINT64 uint64_t; -typedef INT8 int8_t; -typedef INT16 int16_t; -typedef LONG32 int32_t; -typedef INT64 int64_t; -#endif - - -/* define some commodity macros for Dump/Restore functionality */ -#ifndef SIMCLIST_NO_DUMPRESTORE -/* write() decorated with error checking logic */ -#define WRITE_ERRCHECK(fd, msgbuf, msglen) do { \ - if (write(fd, msgbuf, msglen) < 0) return -1; \ - } while (0); -/* READ_ERRCHECK() decorated with error checking logic */ -#define READ_ERRCHECK(fd, msgbuf, msglen) do { \ - if (read(fd, msgbuf, msglen) != msglen) { \ - /*errno = EPROTO;*/ \ - return -1; \ - } \ - } while (0); - -/* convert 64bit integers from host to network format */ -#define hton64(x) (\ - htons(1) == 1 ? \ - (uint64_t)x /* big endian */ \ - : /* little endian */ \ - ((uint64_t)((((uint64_t)(x) & 0xff00000000000000ULL) >> 56) | \ - (((uint64_t)(x) & 0x00ff000000000000ULL) >> 40) | \ - (((uint64_t)(x) & 0x0000ff0000000000ULL) >> 24) | \ - (((uint64_t)(x) & 0x000000ff00000000ULL) >> 8) | \ - (((uint64_t)(x) & 0x00000000ff000000ULL) << 8) | \ - (((uint64_t)(x) & 0x0000000000ff0000ULL) << 24) | \ - (((uint64_t)(x) & 0x000000000000ff00ULL) << 40) | \ - (((uint64_t)(x) & 0x00000000000000ffULL) << 56))) \ - ) - -/* convert 64bit integers from network to host format */ -#define ntoh64(x) (hton64(x)) -#endif - -/* some OSes don't have EPROTO (eg OpenBSD) */ -#ifndef EPROTO -#define EPROTO EIO -#endif - -#ifdef SIMCLIST_WITH_THREADS -/* limit (approx) to the number of threads running -* for threaded operations. Only meant when -* SIMCLIST_WITH_THREADS is defined */ -#define SIMCLIST_MAXTHREADS 2 -#endif - -/* -* how many elems to keep as spare. During a deletion, an element -* can be saved in a "free-list", not free()d immediately. When -* latter insertions are performed, spare elems can be used instead -* of malloc()ing new elems. -* -* about this param, some values for appending -* 10 million elems into an empty list: -* (#, time[sec], gain[%], gain/no[%]) -* 0 2,164 0,00 0,00 <-- feature disabled -* 1 1,815 34,9 34,9 -* 2 1,446 71,8 35,9 <-- MAX gain/no -* 3 1,347 81,7 27,23 -* 5 1,213 95,1 19,02 -* 8 1,064 110,0 13,75 -* 10 1,015 114,9 11,49 <-- MAX gain w/ likely sol -* 15 1,019 114,5 7,63 -* 25 0,985 117,9 4,72 -* 50 1,088 107,6 2,15 -* 75 1,016 114,8 1,53 -* 100 0,988 117,6 1,18 -* 150 1,022 114,2 0,76 -* 200 0,939 122,5 0,61 <-- MIN time -*/ -#ifndef SIMCLIST_MAX_SPARE_ELEMS -#define SIMCLIST_MAX_SPARE_ELEMS 5 -#endif - - -#ifdef SIMCLIST_WITH_THREADS -#include -#endif - -#include "simclist.h" - - -/* minumum number of elements for sorting with quicksort instead of insertion */ -#define SIMCLIST_MINQUICKSORTELS 24 - - -/* list dump declarations */ -#define SIMCLIST_DUMPFORMAT_VERSION 1 /* (short integer) version of fileformat managed by _dump* and _restore* functions */ - -// @todo this is not correct, the header would be padded by default on version for 2 more bytes, and treating the structure as 30 bytes would cut the last 2 bytes off the listhash at the end -#define SIMCLIST_DUMPFORMAT_HEADERLEN 30 /* length of the header */ - -/* header for a list dump */ -struct ks_list_dump_header_s { - uint16_t ver; /* version */ - int32_t timestamp_sec; /* dump timestamp, seconds since UNIX Epoch */ - int32_t timestamp_usec; /* dump timestamp, microseconds since timestamp_sec */ - int32_t rndterm; /* random value terminator -- terminates the data sequence */ - - uint32_t totlistlen; /* sum of every element' size, bytes */ - uint32_t numels; /* number of elements */ - uint32_t elemlen; /* bytes length of an element, for constant-size lists, <= 0 otherwise */ - int32_t listhash; /* hash of the list at the time of dumping, or 0 if to be ignored */ -}; - - - -/* deletes tmp from list, with care wrt its position (head, tail, middle) */ -static int ks_list_drop_elem(ks_list_t *restrict l, struct ks_list_entry_s *tmp, unsigned int pos); - -/* set default values for initialized lists */ -static int ks_list_attributes_setdefaults(ks_list_t *restrict l); - -/* check whether the list internal REPresentation is valid -- Costs O(n) */ -static int ks_list_repOk(const ks_list_t *restrict l); - -/* check whether the list attribute set is valid -- Costs O(1) */ -static int ks_list_attrOk(const ks_list_t *restrict l); - -/* do not inline, this is recursive */ -static void ks_list_sort_quicksort(ks_list_t *restrict l, int versus, - unsigned int first, struct ks_list_entry_s *fel, - unsigned int last, struct ks_list_entry_s *lel); - -static inline void ks_list_sort_selectionsort(ks_list_t *restrict l, int versus, - unsigned int first, struct ks_list_entry_s *fel, - unsigned int last, struct ks_list_entry_s *lel); - -static void *ks_list_get_minmax(const ks_list_t *restrict l, int versus); - -static inline struct ks_list_entry_s *ks_list_findpos(const ks_list_t *restrict l, int posstart); - -/* -* Random Number Generator -* -* The user is expected to seed the RNG (ie call srand()) if -* SIMCLIST_SYSTEM_RNG is defined. -* -* Otherwise, a self-contained RNG based on LCG is used; see -* http://en.wikipedia.org/wiki/Linear_congruential_generator . -* -* Facts pro local RNG: -* 1. no need for the user to call srand() on his own -* 2. very fast, possibly faster than OS -* 3. avoid interference with user's RNG -* -* Facts pro system RNG: -* 1. may be more accurate (irrelevant for SimCList randno purposes) -* 2. why reinvent the wheel -* -* Default to local RNG for user's ease of use. -*/ - -#ifdef SIMCLIST_SYSTEM_RNG -/* keep track whether we initialized already (non-0) or not (0) */ -static unsigned random_seed = 0; - -/* use local RNG */ -static inline void seed_random(void) { - if (random_seed == 0) - random_seed = (unsigned)getpid() ^ (unsigned)time(NULL); -} - -static inline long get_random(void) { - random_seed = (1664525 * random_seed + 1013904223); - return random_seed; -} - -#else -/* use OS's random generator */ -# define seed_random() -# define get_random() (rand()) -#endif - - -static void ks_list_cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - ks_list_t *l = (ks_list_t *)ptr; - - switch (action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - ks_list_clear(l); - ks_rwl_write_lock(l->lock); - for (unsigned int i = 0; i < l->spareelsnum; i++) ks_pool_free(&l->spareels[i]); - l->spareelsnum = 0; - ks_pool_free(&l->spareels); - ks_pool_free(&l->head_sentinel); - ks_pool_free(&l->tail_sentinel); - ks_rwl_write_unlock(l->lock); - ks_rwl_destroy(&l->lock); - break; - case KS_MPCL_DESTROY: - break; - } -} - -/* list initialization */ -KS_DECLARE(ks_status_t) ks_list_create(ks_list_t **list, ks_pool_t *pool) { - ks_list_t *l = NULL; - - ks_assert(list); - ks_assert(pool); - - seed_random(); - - l = ks_pool_alloc(pool, sizeof(ks_list_t)); - ks_assert(l); - - l->numels = 0; - - ks_rwl_create(&l->lock, pool); - ks_assert(l->lock); - - /* head/tail sentinels and mid pointer */ - l->head_sentinel = (struct ks_list_entry_s *)ks_pool_alloc(pool, sizeof(struct ks_list_entry_s)); - l->tail_sentinel = (struct ks_list_entry_s *)ks_pool_alloc(pool, sizeof(struct ks_list_entry_s)); - l->head_sentinel->next = l->tail_sentinel; - l->tail_sentinel->prev = l->head_sentinel; - l->head_sentinel->prev = l->tail_sentinel->next = l->mid = NULL; - l->head_sentinel->data = l->tail_sentinel->data = NULL; - - /* iteration attributes */ - l->iter_active = 0; - l->iter_pos = 0; - l->iter_curentry = NULL; - - /* free-list attributes */ - l->spareels = (struct ks_list_entry_s **)ks_pool_alloc(pool, SIMCLIST_MAX_SPARE_ELEMS * sizeof(struct ks_list_entry_s *)); - l->spareelsnum = 0; - -#ifdef SIMCLIST_WITH_THREADS - l->threadcount = 0; -#endif - - ks_list_attributes_setdefaults(l); - - ks_assert(ks_list_repOk(l)); - ks_assert(ks_list_attrOk(l)); - - ks_pool_set_cleanup(l, NULL, ks_list_cleanup); - - *list = l; - return KS_STATUS_SUCCESS; -} - -KS_DECLARE(ks_status_t) ks_list_destroy(ks_list_t **list) { - ks_list_t *l = NULL; - - ks_assert(list); - - l = *list; - *list = NULL; - if (!l) return KS_STATUS_FAIL; - - ks_pool_free(&l); - - return KS_STATUS_SUCCESS; -} - -int ks_list_attributes_setdefaults(ks_list_t *restrict l) { - l->attrs.comparator = NULL; - l->attrs.seeker = NULL; - - /* also free() element data when removing and element from the list */ - l->attrs.meter = NULL; - l->attrs.copy_data = 0; - - l->attrs.hasher = NULL; - - /* serializer/unserializer */ - l->attrs.serializer = NULL; - l->attrs.unserializer = NULL; - - ks_assert(ks_list_attrOk(l)); - - return 0; -} - -/* setting list properties */ -int ks_list_attributes_comparator(ks_list_t *restrict l, element_comparator comparator_fun) { - if (l == NULL) return -1; - - ks_rwl_write_lock(l->lock); - l->attrs.comparator = comparator_fun; - - ks_assert(ks_list_attrOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -int ks_list_attributes_seeker(ks_list_t *restrict l, element_seeker seeker_fun) { - if (l == NULL) return -1; - - ks_rwl_write_lock(l->lock); - l->attrs.seeker = seeker_fun; - - ks_assert(ks_list_attrOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -int ks_list_attributes_copy(ks_list_t *restrict l, element_meter metric_fun, int copy_data) { - if (l == NULL || (metric_fun == NULL && copy_data != 0)) return -1; - - ks_rwl_write_lock(l->lock); - l->attrs.meter = metric_fun; - l->attrs.copy_data = copy_data; - - ks_assert(ks_list_attrOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -int ks_list_attributes_hash_computer(ks_list_t *restrict l, element_hash_computer hash_computer_fun) { - if (l == NULL) return -1; - - ks_rwl_write_lock(l->lock); - l->attrs.hasher = hash_computer_fun; - - ks_assert(ks_list_attrOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -int ks_list_attributes_serializer(ks_list_t *restrict l, element_serializer serializer_fun) { - if (l == NULL) return -1; - - ks_rwl_write_lock(l->lock); - l->attrs.serializer = serializer_fun; - - ks_assert(ks_list_attrOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -int ks_list_attributes_unserializer(ks_list_t *restrict l, element_unserializer unserializer_fun) { - if (l == NULL) return -1; - - ks_rwl_write_lock(l->lock); - l->attrs.unserializer = unserializer_fun; - - ks_assert(ks_list_attrOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -KS_DECLARE(int) ks_list_append(ks_list_t *restrict l, const void *data) { - return ks_list_insert_at(l, data, l->numels); -} - -KS_DECLARE(int) ks_list_prepend(ks_list_t *restrict l, const void *data) { - return ks_list_insert_at(l, data, 0); -} - -KS_DECLARE(void *) ks_list_fetch(ks_list_t *restrict l) { - return ks_list_extract_at(l, 0); -} - -KS_DECLARE(void *) ks_list_get_at(const ks_list_t *restrict l, unsigned int pos) { - struct ks_list_entry_s *tmp; - void *data = NULL; - - ks_rwl_read_lock(l->lock); - tmp = ks_list_findpos(l, pos); - data = tmp != NULL ? tmp->data : NULL; - ks_rwl_read_unlock(l->lock); - - return data; -} - -KS_DECLARE(void *) ks_list_get_max(const ks_list_t *restrict l) { - return ks_list_get_minmax(l, +1); -} - -KS_DECLARE(void *) ks_list_get_min(const ks_list_t *restrict l) { - return ks_list_get_minmax(l, -1); -} - -/* REQUIRES {list->numels >= 1} -* return the min (versus < 0) or max value (v > 0) in l */ -static void *ks_list_get_minmax(const ks_list_t *restrict l, int versus) { - void *curminmax; - struct ks_list_entry_s *s; - - if (l->attrs.comparator == NULL || l->numels == 0) - return NULL; - - ks_rwl_read_lock(l->lock); - curminmax = l->head_sentinel->next->data; - for (s = l->head_sentinel->next->next; s != l->tail_sentinel; s = s->next) { - if (l->attrs.comparator(curminmax, s->data) * versus > 0) - curminmax = s->data; - } - ks_rwl_read_unlock(l->lock); - - return curminmax; -} - -/* set tmp to point to element at index posstart in l */ -static inline struct ks_list_entry_s *ks_list_findpos(const ks_list_t *restrict l, int posstart) { - struct ks_list_entry_s *ptr; - float x; - int i; - - /* accept 1 slot overflow for fetching head and tail sentinels */ - if (posstart < -1 || posstart >(int)l->numels) return NULL; - - x = (float)(posstart + 1) / l->numels; - if (x <= 0.25) { - /* first quarter: get to posstart from head */ - for (i = -1, ptr = l->head_sentinel; i < posstart; ptr = ptr->next, i++); - } - else if (x < 0.5) { - /* second quarter: get to posstart from mid */ - for (i = (l->numels - 1) / 2, ptr = l->mid; i > posstart; ptr = ptr->prev, i--); - } - else if (x <= 0.75) { - /* third quarter: get to posstart from mid */ - for (i = (l->numels - 1) / 2, ptr = l->mid; i < posstart; ptr = ptr->next, i++); - } - else { - /* fourth quarter: get to posstart from tail */ - for (i = l->numels, ptr = l->tail_sentinel; i > posstart; ptr = ptr->prev, i--); - } - - return ptr; -} - -KS_DECLARE(void *) ks_list_extract_at(ks_list_t *restrict l, unsigned int pos) { - struct ks_list_entry_s *tmp; - void *data; - - if (l->iter_active || pos >= l->numels) return NULL; - - ks_rwl_write_lock(l->lock); - tmp = ks_list_findpos(l, pos); - data = tmp->data; - - tmp->data = NULL; /* save data from ks_list_drop_elem() free() */ - ks_list_drop_elem(l, tmp, pos); - l->numels--; - - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return data; -} - -KS_DECLARE(int) ks_list_insert_at(ks_list_t *restrict l, const void *data, unsigned int pos) { - ks_pool_t *pool = NULL; - struct ks_list_entry_s *lent, *succ, *prec; - - if (l->iter_active || pos > l->numels) return -1; - - pool = ks_pool_get(l); - - ks_rwl_write_lock(l->lock); - /* this code optimizes malloc() with a free-list */ - if (l->spareelsnum > 0) { - lent = l->spareels[l->spareelsnum - 1]; - l->spareelsnum--; - } - else { - lent = (struct ks_list_entry_s *)ks_pool_alloc(pool, sizeof(struct ks_list_entry_s)); - ks_assert(lent); - } - - if (l->attrs.copy_data) { - /* make room for user' data (has to be copied) */ - ks_size_t datalen = l->attrs.meter(data); - lent->data = (struct ks_list_entry_s *)ks_pool_alloc(pool, datalen); - memcpy(lent->data, data, datalen); - } - else { - lent->data = (void*)data; - } - - /* actually append element */ - prec = ks_list_findpos(l, pos - 1); - succ = prec->next; - - prec->next = lent; - lent->prev = prec; - lent->next = succ; - succ->prev = lent; - - l->numels++; - - /* fix mid pointer */ - if (l->numels == 1) { /* first element, set pointer */ - l->mid = lent; - } - else if (l->numels % 2) { /* now odd */ - if (pos >= (l->numels - 1) / 2) l->mid = l->mid->next; - } - else { /* now even */ - if (pos <= (l->numels - 1) / 2) l->mid = l->mid->prev; - } - - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 1; -} - -KS_DECLARE(int) ks_list_delete(ks_list_t *restrict l, const void *data) { - int pos, r; - int ret = 0; - - ks_rwl_write_lock(l->lock); - - pos = ks_list_locate(l, data, KS_TRUE); - if (pos < 0) { - ret = -1; - goto done; - } - - r = ks_list_delete_at(l, pos); - if (r < 0) ret = -1; - -done: - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return ret; -} - -KS_DECLARE(int) ks_list_delete_at(ks_list_t *restrict l, unsigned int pos) { - struct ks_list_entry_s *delendo; - - if (l->iter_active || pos >= l->numels) return -1; - - ks_rwl_write_lock(l->lock); - - delendo = ks_list_findpos(l, pos); - - ks_list_drop_elem(l, delendo, pos); - - l->numels--; - - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -KS_DECLARE(int) ks_list_delete_iterator(ks_list_t *restrict l) { - struct ks_list_entry_s *delendo; - - if (!l->iter_active || l->iter_pos > l->numels) return -1; - - ks_rwl_write_lock(l->lock); - - delendo = ks_list_findpos(l, l->iter_pos - 1); - - ks_list_drop_elem(l, delendo, l->iter_pos - 1); - - l->numels--; - - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -KS_DECLARE(int) ks_list_delete_range(ks_list_t *restrict l, unsigned int posstart, unsigned int posend) { - struct ks_list_entry_s *lastvalid, *tmp, *tmp2; - unsigned int numdel, midposafter, i; - int movedx; - - if (l->iter_active || posend < posstart || posend >= l->numels) return -1; - - numdel = posend - posstart + 1; - if (numdel == l->numels) return ks_list_clear(l); - - ks_rwl_write_lock(l->lock); - - tmp = ks_list_findpos(l, posstart); /* first el to be deleted */ - lastvalid = tmp->prev; /* last valid element */ - - midposafter = (l->numels - 1 - numdel) / 2; - - midposafter = midposafter < posstart ? midposafter : midposafter + numdel; - movedx = midposafter - (l->numels - 1) / 2; - - if (movedx > 0) { /* move right */ - for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->next, i++); - } - else { /* move left */ - movedx = -movedx; - for (i = 0; i < (unsigned int)movedx; l->mid = l->mid->prev, i++); - } - - ks_assert(posstart == 0 || lastvalid != l->head_sentinel); - i = posstart; - if (l->attrs.copy_data) { - /* also free element data */ - for (; i <= posend; i++) { - tmp2 = tmp; - tmp = tmp->next; - if (tmp2->data != NULL) ks_pool_free(&tmp2->data); - if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { - l->spareels[l->spareelsnum++] = tmp2; - } - else { - ks_pool_free(&tmp2); - } - } - } - else { - /* only free containers */ - for (; i <= posend; i++) { - tmp2 = tmp; - tmp = tmp->next; - if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { - l->spareels[l->spareelsnum++] = tmp2; - } - else { - ks_pool_free(&tmp2); - } - } - } - ks_assert(i == posend + 1 && (posend != l->numels || tmp == l->tail_sentinel)); - - lastvalid->next = tmp; - tmp->prev = lastvalid; - - l->numels -= posend - posstart + 1; - - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return numdel; -} - -KS_DECLARE(int) ks_list_clear(ks_list_t *restrict l) { - struct ks_list_entry_s *s; - int numels; - - ks_rwl_write_lock(l->lock); - - /* will be returned */ - numels = (int)l->numels; - - if (l->iter_active) { - numels = -1; - goto done; - } - - if (l->attrs.copy_data) { /* also free user data */ - /* spare a loop conditional with two loops: spareing elems and freeing elems */ - for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { - /* move elements as spares as long as there is room */ - if (s->data != NULL) ks_pool_free(&s->data); - l->spareels[l->spareelsnum++] = s; - } - while (s != l->tail_sentinel) { - /* free the remaining elems */ - if (s->data != NULL) ks_pool_free(&s->data); - s = s->next; - ks_pool_free(&s->prev); - } - l->head_sentinel->next = l->tail_sentinel; - l->tail_sentinel->prev = l->head_sentinel; - } - else { /* only free element containers */ - /* spare a loop conditional with two loops: spareing elems and freeing elems */ - for (s = l->head_sentinel->next; l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS && s != l->tail_sentinel; s = s->next) { - /* move elements as spares as long as there is room */ - l->spareels[l->spareelsnum++] = s; - } - while (s != l->tail_sentinel) { - /* free the remaining elems */ - s = s->next; - ks_pool_free(&s->prev); - } - l->head_sentinel->next = l->tail_sentinel; - l->tail_sentinel->prev = l->head_sentinel; - } - l->numels = 0; - l->mid = NULL; - -done: - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return numels; -} - -KS_DECLARE(unsigned int) ks_list_size(const ks_list_t *restrict l) { - return l->numels; -} - -KS_DECLARE(int) ks_list_empty(const ks_list_t *restrict l) { - return (l->numels == 0); -} - -KS_DECLARE(int) ks_list_locate(const ks_list_t *restrict l, const void *data, ks_bool_t prelocked) { - struct ks_list_entry_s *el; - int pos = 0; - - if (!prelocked) ks_rwl_read_lock(l->lock); - - if (l->attrs.comparator != NULL) { - /* use comparator */ - for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) { - if (l->attrs.comparator(data, el->data) == 0) break; - } - } - else { - /* compare references */ - for (el = l->head_sentinel->next; el != l->tail_sentinel; el = el->next, pos++) { - if (el->data == data) break; - } - } - if (!prelocked) ks_rwl_read_unlock(l->lock); - if (el == l->tail_sentinel) return -1; - - return pos; -} - -KS_DECLARE(void *) ks_list_seek(ks_list_t *restrict l, const void *indicator) { - const struct ks_list_entry_s *iter; - void *ret = NULL; - - if (l->attrs.seeker == NULL) return NULL; - - ks_rwl_read_lock(l->lock); - - for (iter = l->head_sentinel->next; iter != l->tail_sentinel; iter = iter->next) { - if (l->attrs.seeker(iter->data, indicator) != 0) { - ret = iter->data; - break; - } - } - - ks_rwl_read_unlock(l->lock); - - return ret; -} - -KS_DECLARE(int) ks_list_contains(const ks_list_t *restrict l, const void *data) { - return (ks_list_locate(l, data, KS_FALSE) >= 0); -} - -KS_DECLARE(int) ks_list_concat(const ks_list_t *l1, const ks_list_t *l2, ks_list_t *restrict dest) { - ks_pool_t *pool = NULL; - struct ks_list_entry_s *el, *srcel; - unsigned int cnt; - int err; - - - if (l1 == NULL || l2 == NULL || dest == NULL || l1 == dest || l2 == dest) - return -1; - - //ks_list_init(dest); - ks_rwl_read_lock(l1->lock); - ks_rwl_read_lock(l2->lock); - ks_rwl_write_lock(dest->lock); - - dest->numels = l1->numels + l2->numels; - if (dest->numels == 0) goto done; - - pool = ks_pool_get(dest); - - /* copy list1 */ - srcel = l1->head_sentinel->next; - el = dest->head_sentinel; - while (srcel != l1->tail_sentinel) { - el->next = (struct ks_list_entry_s *)ks_pool_alloc(pool, sizeof(struct ks_list_entry_s)); - el->next->prev = el; - el = el->next; - el->data = srcel->data; - srcel = srcel->next; - } - dest->mid = el; /* approximate position (adjust later) */ - /* copy list 2 */ - srcel = l2->head_sentinel->next; - while (srcel != l2->tail_sentinel) { - el->next = (struct ks_list_entry_s *)ks_pool_alloc(pool, sizeof(struct ks_list_entry_s)); - el->next->prev = el; - el = el->next; - el->data = srcel->data; - srcel = srcel->next; - } - el->next = dest->tail_sentinel; - dest->tail_sentinel->prev = el; - - /* fix mid pointer */ - err = l2->numels - l1->numels; - if ((err + 1) / 2 > 0) { /* correct pos RIGHT (err-1)/2 moves */ - err = (err + 1) / 2; - for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->next; - } - else if (err / 2 < 0) { /* correct pos LEFT (err/2)-1 moves */ - err = -err / 2; - for (cnt = 0; cnt < (unsigned int)err; cnt++) dest->mid = dest->mid->prev; - } - -done: - - ks_assert(!(ks_list_repOk(l1) && ks_list_repOk(l2)) || ks_list_repOk(dest)); - - ks_rwl_write_unlock(dest->lock); - ks_rwl_read_unlock(l2->lock); - ks_rwl_read_unlock(l1->lock); - - return 0; -} - -KS_DECLARE(int) ks_list_sort(ks_list_t *restrict l, int versus) { - if (l->iter_active || l->attrs.comparator == NULL) /* cannot modify list in the middle of an iteration */ - return -1; - - if (l->numels <= 1) - return 0; - - ks_rwl_write_lock(l->lock); - ks_list_sort_quicksort(l, versus, 0, l->head_sentinel->next, l->numels - 1, l->tail_sentinel->prev); - - ks_assert(ks_list_repOk(l)); - - ks_rwl_write_unlock(l->lock); - - return 0; -} - -#ifdef SIMCLIST_WITH_THREADS -struct ks_list_sort_wrappedparams { - ks_list_t *restrict l; - int versus; - unsigned int first, last; - struct ks_list_entry_s *fel, *lel; -}; - -static void *ks_list_sort_quicksort_threadwrapper(void *wrapped_params) { - struct ks_list_sort_wrappedparams *wp = (struct ks_list_sort_wrappedparams *)wrapped_params; - ks_list_sort_quicksort(wp->l, wp->versus, wp->first, wp->fel, wp->last, wp->lel); - ks_pool_free(&wp); - pthread_exit(NULL); - return NULL; -} -#endif - -static inline void ks_list_sort_selectionsort(ks_list_t *restrict l, int versus, - unsigned int first, struct ks_list_entry_s *fel, - unsigned int last, struct ks_list_entry_s *lel) { - struct ks_list_entry_s *cursor, *toswap, *firstunsorted; - void *tmpdata; - - if (last <= first) /* <= 1-element lists are always sorted */ - return; - - for (firstunsorted = fel; firstunsorted != lel; firstunsorted = firstunsorted->next) { - /* find min or max in the remainder of the list */ - for (toswap = firstunsorted, cursor = firstunsorted->next; cursor != lel->next; cursor = cursor->next) - if (l->attrs.comparator(toswap->data, cursor->data) * -versus > 0) toswap = cursor; - if (toswap != firstunsorted) { /* swap firstunsorted with toswap */ - tmpdata = firstunsorted->data; - firstunsorted->data = toswap->data; - toswap->data = tmpdata; - } - } -} - -static void ks_list_sort_quicksort(ks_list_t *restrict l, int versus, - unsigned int first, struct ks_list_entry_s *fel, - unsigned int last, struct ks_list_entry_s *lel) { - unsigned int pivotid; - unsigned int i; - register struct ks_list_entry_s *pivot; - struct ks_list_entry_s *left, *right; - void *tmpdata; -#ifdef SIMCLIST_WITH_THREADS - pthread_t tid; - int traised; -#endif - - - if (last <= first) /* <= 1-element lists are always sorted */ - return; - - if (last - first + 1 <= SIMCLIST_MINQUICKSORTELS) { - ks_list_sort_selectionsort(l, versus, first, fel, last, lel); - return; - } - - /* base of iteration: one element list */ - if (!(last > first)) return; - - pivotid = (get_random() % (last - first + 1)); - /* pivotid = (last - first + 1) / 2; */ - - /* find pivot */ - if (pivotid < (last - first + 1) / 2) { - for (i = 0, pivot = fel; i < pivotid; pivot = pivot->next, i++); - } - else { - for (i = last - first, pivot = lel; i > pivotid; pivot = pivot->prev, i--); - } - - /* smaller PIVOT bigger */ - left = fel; - right = lel; - /* iterate --- left ---> PIV <--- right --- */ - while (left != pivot && right != pivot) { - for (; left != pivot && (l->attrs.comparator(left->data, pivot->data) * -versus <= 0); left = left->next); - /* left points to a smaller element, or to pivot */ - for (; right != pivot && (l->attrs.comparator(right->data, pivot->data) * -versus >= 0); right = right->prev); - /* right points to a bigger element, or to pivot */ - if (left != pivot && right != pivot) { - /* swap, then move iterators */ - tmpdata = left->data; - left->data = right->data; - right->data = tmpdata; - - left = left->next; - right = right->prev; - } - } - - /* now either left points to pivot (end run), or right */ - if (right == pivot) { /* left part longer */ - while (left != pivot) { - if (l->attrs.comparator(left->data, pivot->data) * -versus > 0) { - tmpdata = left->data; - left->data = pivot->prev->data; - pivot->prev->data = pivot->data; - pivot->data = tmpdata; - pivot = pivot->prev; - pivotid--; - if (pivot == left) break; - } - else { - left = left->next; - } - } - } - else { /* right part longer */ - while (right != pivot) { - if (l->attrs.comparator(right->data, pivot->data) * -versus < 0) { - /* move current right before pivot */ - tmpdata = right->data; - right->data = pivot->next->data; - pivot->next->data = pivot->data; - pivot->data = tmpdata; - pivot = pivot->next; - pivotid++; - if (pivot == right) break; - } - else { - right = right->prev; - } - } - } - - /* sort sublists A and B : |---A---| pivot |---B---| */ - -#ifdef SIMCLIST_WITH_THREADS - traised = 0; - if (pivotid > 0) { - /* prepare wrapped args, then start thread */ - if (l->threadcount < SIMCLIST_MAXTHREADS - 1) { - struct ks_list_sort_wrappedparams *wp = (struct ks_list_sort_wrappedparams *)ks_pool_alloc(ks_pool_get(l), sizeof(struct ks_list_sort_wrappedparams)); - l->threadcount++; - traised = 1; - wp->l = l; - wp->versus = versus; - wp->first = first; - wp->fel = fel; - wp->last = first + pivotid - 1; - wp->lel = pivot->prev; - if (pthread_create(&tid, NULL, ks_list_sort_quicksort_threadwrapper, wp) != 0) { - ks_pool_free(&wp); - traised = 0; - ks_list_sort_quicksort(l, versus, first, fel, first + pivotid - 1, pivot->prev); - } - } - else { - ks_list_sort_quicksort(l, versus, first, fel, first + pivotid - 1, pivot->prev); - } - } - if (first + pivotid < last) ks_list_sort_quicksort(l, versus, first + pivotid + 1, pivot->next, last, lel); - if (traised) { - pthread_join(tid, (void **)NULL); - l->threadcount--; - } -#else - if (pivotid > 0) ks_list_sort_quicksort(l, versus, first, fel, first + pivotid - 1, pivot->prev); - if (first + pivotid < last) ks_list_sort_quicksort(l, versus, first + pivotid + 1, pivot->next, last, lel); -#endif -} - -KS_DECLARE(int) ks_list_iterator_start(ks_list_t *restrict l) { - if (l->iter_active) return 0; - ks_rwl_write_lock(l->lock); - l->iter_pos = 0; - l->iter_active = 1; - l->iter_curentry = l->head_sentinel->next; - ks_rwl_write_unlock(l->lock); - return 1; -} - -KS_DECLARE(void *) ks_list_iterator_next(ks_list_t *restrict l) { - void *toret; - - if (!l->iter_active) return NULL; - - ks_rwl_write_lock(l->lock); - toret = l->iter_curentry->data; - l->iter_curentry = l->iter_curentry->next; - l->iter_pos++; - ks_rwl_write_unlock(l->lock); - - return toret; -} - -KS_DECLARE(int) ks_list_iterator_hasnext(const ks_list_t *restrict l) { - int ret = 0; - if (!l->iter_active) return 0; - ks_rwl_read_lock(l->lock); - ret = (l->iter_pos < l->numels); - ks_rwl_read_unlock(l->lock); - return ret; -} - -KS_DECLARE(int) ks_list_iterator_stop(ks_list_t *restrict l) { - if (!l->iter_active) return 0; - ks_rwl_write_lock(l->lock); - l->iter_pos = 0; - l->iter_active = 0; - ks_rwl_write_unlock(l->lock); - return 1; -} - -KS_DECLARE(int) ks_list_hash(const ks_list_t *restrict l, ks_list_hash_t *restrict hash) { - struct ks_list_entry_s *x; - ks_list_hash_t tmphash; - int ret = 0; - - ks_assert(hash != NULL); - - ks_rwl_read_lock(l->lock); - - tmphash = l->numels * 2 + 100; - if (l->attrs.hasher == NULL) { -#ifdef SIMCLIST_ALLOW_LOCATIONBASED_HASHES - /* ENABLE WITH CARE !! */ - #warning "Memlocation-based hash is consistent only for testing modification in the same program run." - int i; - - /* only use element references */ - for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { - for (i = 0; i < sizeof(x->data); i++) { - tmphash += (tmphash ^ (uintptr_t)x->data); - } - tmphash += tmphash % l->numels; - } -#else - ret = -1; -#endif - } - else { - /* hash each element with the user-given function */ - for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { - tmphash += tmphash ^ l->attrs.hasher(x->data); - tmphash += tmphash % l->numels; - } - } - - ks_rwl_read_unlock(l->lock); - - *hash = tmphash; - - return ret; -} - -#ifndef SIMCLIST_NO_DUMPRESTORE -int ks_list_dump_getinfo_filedescriptor(int fd, ks_list_dump_info_t *restrict info) { - int32_t terminator_head, terminator_tail; - uint32_t elemlen; - off_t hop; - - - /* version */ - READ_ERRCHECK(fd, &info->version, sizeof(info->version)); - info->version = ntohs(info->version); - if (info->version > SIMCLIST_DUMPFORMAT_VERSION) { - errno = EILSEQ; - return -1; - } - - /* timestamp.tv_sec and timestamp.tv_usec */ - READ_ERRCHECK(fd, &info->timestamp.tv_sec, sizeof(info->timestamp.tv_sec)); - info->timestamp.tv_sec = ntohl(info->timestamp.tv_sec); - READ_ERRCHECK(fd, &info->timestamp.tv_usec, sizeof(info->timestamp.tv_usec)); - info->timestamp.tv_usec = ntohl(info->timestamp.tv_usec); - - /* list terminator (to check thereafter) */ - READ_ERRCHECK(fd, &terminator_head, sizeof(terminator_head)); - terminator_head = ntohl(terminator_head); - - /* list size */ - READ_ERRCHECK(fd, &info->list_size, sizeof(info->list_size)); - info->list_size = ntohl(info->list_size); - - /* number of elements */ - READ_ERRCHECK(fd, &info->list_numels, sizeof(info->list_numels)); - info->list_numels = ntohl(info->list_numels); - - /* length of each element (for checking for consistency) */ - READ_ERRCHECK(fd, &elemlen, sizeof(elemlen)); - elemlen = ntohl(elemlen); - - /* list hash */ - READ_ERRCHECK(fd, &info->list_hash, sizeof(info->list_hash)); - info->list_hash = ntohl(info->list_hash); - - /* check consistency */ - if (elemlen > 0) { - /* constant length, hop by size only */ - hop = info->list_size; - } - else { - /* non-constant length, hop by size + all element length blocks */ - hop = info->list_size + elemlen*info->list_numels; - } - if (lseek(fd, hop, SEEK_CUR) == -1) { - return -1; - } - - /* read the trailing value and compare with terminator_head */ - READ_ERRCHECK(fd, &terminator_tail, sizeof(terminator_tail)); - terminator_tail = ntohl(terminator_tail); - - if (terminator_head == terminator_tail) - info->consistent = 1; - else - info->consistent = 0; - - return 0; -} - -int ks_list_dump_getinfo_file(const char *restrict filename, ks_list_dump_info_t *restrict info) { - int fd, ret; - - fd = open(filename, O_RDONLY, 0); - if (fd < 0) return -1; - - ret = ks_list_dump_getinfo_filedescriptor(fd, info); - close(fd); - - return ret; -} - -int ks_list_dump_filedescriptor(const ks_list_t *restrict l, int fd, ks_size_t *restrict len) { - struct ks_list_entry_s *x; - void *ser_buf; - uint32_t bufsize; - struct timeval timeofday; - struct ks_list_dump_header_s header; - - if (l->attrs.meter == NULL && l->attrs.serializer == NULL) { - errno = ENOTTY; - return -1; - } - - /**** DUMP FORMAT **** - - [ ver timestamp | totlen numels elemlen hash | DATA ] - - where DATA can be: - @ for constant-size list (element size is constant; elemlen > 0) - [ elem elem ... elem ] - @ for other lists (element size dictated by element_meter each time; elemlen <= 0) - [ size elem size elem ... size elem ] - - all integers are encoded in NETWORK BYTE FORMAT - *****/ - - - /* prepare HEADER */ - /* version */ - header.ver = htons(SIMCLIST_DUMPFORMAT_VERSION); - - /* timestamp */ - gettimeofday(&timeofday, NULL); - header.timestamp_sec = htonl(timeofday.tv_sec); - header.timestamp_usec = htonl(timeofday.tv_usec); - - header.rndterm = htonl((int32_t)get_random()); - - /* total list size is postprocessed afterwards */ - - /* number of elements */ - header.numels = htonl(l->numels); - - /* include an hash, if possible */ - if (l->attrs.hasher != NULL) { - if (htonl(ks_list_hash(l, &header.listhash)) != 0) { - /* could not compute list hash! */ - return -1; - } - } - else { - header.listhash = htonl(0); - } - - header.totlistlen = header.elemlen = 0; - - /* leave room for the header at the beginning of the file */ - if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) { - /* errno set by lseek() */ - return -1; - } - - /* write CONTENT */ - if (l->numels > 0) { - /* SPECULATE that the list has constant element size */ - - if (l->attrs.serializer != NULL) { /* user user-specified serializer */ - /* get preliminary length of serialized element in header.elemlen */ - ser_buf = l->attrs.serializer(l->head_sentinel->next->data, &header.elemlen); - ks_pool_free(&ser_buf); - /* request custom serialization of each element */ - for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { - ser_buf = l->attrs.serializer(x->data, &bufsize); - header.totlistlen += bufsize; - if (header.elemlen != 0) { /* continue on speculation */ - if (header.elemlen != bufsize) { - ks_pool_free(&ser_buf); - /* constant element length speculation broken! */ - header.elemlen = 0; - header.totlistlen = 0; - x = l->head_sentinel; - if (lseek(fd, SIMCLIST_DUMPFORMAT_HEADERLEN, SEEK_SET) < 0) { - /* errno set by lseek() */ - return -1; - } - /* restart from the beginning */ - continue; - } - /* speculation confirmed */ - WRITE_ERRCHECK(fd, ser_buf, bufsize); - } - else { /* speculation found broken */ - WRITE_ERRCHECK(fd, &bufsize, sizeof(ks_size_t)); - WRITE_ERRCHECK(fd, ser_buf, bufsize); - } - ks_pool_free(&ser_buf); - } - } - else if (l->attrs.meter != NULL) { - header.elemlen = (uint32_t)l->attrs.meter(l->head_sentinel->next->data); - - /* serialize the element straight from its data */ - for (x = l->head_sentinel->next; x != l->tail_sentinel; x = x->next) { - bufsize = l->attrs.meter(x->data); - header.totlistlen += bufsize; - if (header.elemlen != 0) { - if (header.elemlen != bufsize) { - /* constant element length speculation broken! */ - header.elemlen = 0; - header.totlistlen = 0; - x = l->head_sentinel; - /* restart from the beginning */ - continue; - } - WRITE_ERRCHECK(fd, x->data, bufsize); - } - else { - WRITE_ERRCHECK(fd, &bufsize, sizeof(ks_size_t)); - WRITE_ERRCHECK(fd, x->data, bufsize); - } - } - } - /* adjust endianness */ - header.elemlen = htonl(header.elemlen); - header.totlistlen = htonl(header.totlistlen); - } - - /* write random terminator */ - WRITE_ERRCHECK(fd, &header.rndterm, sizeof(header.rndterm)); /* list terminator */ - - - /* write header */ - lseek(fd, 0, SEEK_SET); - - WRITE_ERRCHECK(fd, &header.ver, sizeof(header.ver)); /* version */ - WRITE_ERRCHECK(fd, &header.timestamp_sec, sizeof(header.timestamp_sec)); /* timestamp seconds */ - WRITE_ERRCHECK(fd, &header.timestamp_usec, sizeof(header.timestamp_usec)); /* timestamp microseconds */ - WRITE_ERRCHECK(fd, &header.rndterm, sizeof(header.rndterm)); /* random terminator */ - - WRITE_ERRCHECK(fd, &header.totlistlen, sizeof(header.totlistlen)); /* total length of elements */ - WRITE_ERRCHECK(fd, &header.numels, sizeof(header.numels)); /* number of elements */ - WRITE_ERRCHECK(fd, &header.elemlen, sizeof(header.elemlen)); /* size of each element, or 0 for independent */ - WRITE_ERRCHECK(fd, &header.listhash, sizeof(header.listhash)); /* list hash, or 0 for "ignore" */ - - - /* possibly store total written length in "len" */ - if (len != NULL) { - *len = sizeof(header) + ntohl(header.totlistlen); - } - - return 0; -} - -int ks_list_restore_filedescriptor(ks_list_t *restrict l, int fd, ks_size_t *restrict len) { - ks_pool_t *pool = NULL; - struct ks_list_dump_header_s header; - unsigned long cnt; - void *buf; - uint32_t elsize, totreadlen, totmemorylen; - - memset(&header, 0, sizeof(header)); - - /* read header */ - - /* version */ - READ_ERRCHECK(fd, &header.ver, sizeof(header.ver)); - header.ver = ntohs(header.ver); - if (header.ver != SIMCLIST_DUMPFORMAT_VERSION) { - errno = EILSEQ; - return -1; - } - - pool = ks_pool_get(l); - - /* timestamp */ - READ_ERRCHECK(fd, &header.timestamp_sec, sizeof(header.timestamp_sec)); - header.timestamp_sec = ntohl(header.timestamp_sec); - READ_ERRCHECK(fd, &header.timestamp_usec, sizeof(header.timestamp_usec)); - header.timestamp_usec = ntohl(header.timestamp_usec); - - /* list terminator */ - READ_ERRCHECK(fd, &header.rndterm, sizeof(header.rndterm)); - - header.rndterm = ntohl(header.rndterm); - - /* total list size */ - READ_ERRCHECK(fd, &header.totlistlen, sizeof(header.totlistlen)); - header.totlistlen = ntohl(header.totlistlen); - - /* number of elements */ - READ_ERRCHECK(fd, &header.numels, sizeof(header.numels)); - header.numels = ntohl(header.numels); - - /* length of every element, or '0' = variable */ - READ_ERRCHECK(fd, &header.elemlen, sizeof(header.elemlen)); - header.elemlen = ntohl(header.elemlen); - - /* list hash, or 0 = 'ignore' */ - READ_ERRCHECK(fd, &header.listhash, sizeof(header.listhash)); - header.listhash = ntohl(header.listhash); - - - /* read content */ - totreadlen = totmemorylen = 0; - if (header.elemlen > 0) { - /* elements have constant size = header.elemlen */ - if (l->attrs.unserializer != NULL) { - /* use unserializer */ - buf = ks_pool_alloc(pool, header.elemlen); - for (cnt = 0; cnt < header.numels; cnt++) { - READ_ERRCHECK(fd, buf, header.elemlen); - ks_list_append(l, l->attrs.unserializer(buf, &elsize)); - totmemorylen += elsize; - } - } - else { - /* copy verbatim into memory */ - for (cnt = 0; cnt < header.numels; cnt++) { - buf = ks_pool_alloc(pool, header.elemlen); - READ_ERRCHECK(fd, buf, header.elemlen); - ks_list_append(l, buf); - } - totmemorylen = header.numels * header.elemlen; - } - totreadlen = header.numels * header.elemlen; - } - else { - /* elements have variable size. Each element is preceded by its size */ - if (l->attrs.unserializer != NULL) { - /* use unserializer */ - for (cnt = 0; cnt < header.numels; cnt++) { - READ_ERRCHECK(fd, &elsize, sizeof(elsize)); - buf = ks_pool_alloc(pool, (ks_size_t)elsize); - READ_ERRCHECK(fd, buf, elsize); - totreadlen += elsize; - ks_list_append(l, l->attrs.unserializer(buf, &elsize)); - totmemorylen += elsize; - } - } - else { - /* copy verbatim into memory */ - for (cnt = 0; cnt < header.numels; cnt++) { - READ_ERRCHECK(fd, &elsize, sizeof(elsize)); - buf = ks_pool_alloc(pool, elsize); - READ_ERRCHECK(fd, buf, elsize); - totreadlen += elsize; - ks_list_append(l, buf); - } - totmemorylen = totreadlen; - } - } - - READ_ERRCHECK(fd, &elsize, sizeof(elsize)); /* read list terminator */ - elsize = ntohl(elsize); - - /* possibly verify the list consistency */ - /* wrt hash */ - /* don't do that - if (header.listhash != 0 && header.listhash != ks_list_hash(l)) { - errno = ECANCELED; - return -1; - } - */ - - /* wrt header */ - if (totreadlen != header.totlistlen && (int32_t)elsize == header.rndterm) { - errno = EPROTO; - return -1; - } - - /* wrt file */ - if (lseek(fd, 0, SEEK_CUR) != lseek(fd, 0, SEEK_END)) { - errno = EPROTO; - return -1; - } - - if (len != NULL) { - *len = totmemorylen; - } - - return 0; -} - -int ks_list_dump_file(const ks_list_t *restrict l, const char *restrict filename, ks_size_t *restrict len) { - int fd, oflag, mode; - -#ifndef _WIN32 - oflag = O_RDWR | O_CREAT | O_TRUNC; - mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; -#else - oflag = _O_RDWR | _O_CREAT | _O_TRUNC; - mode = _S_IRUSR | _S_IWUSR | _S_IRGRP | _S_IROTH; -#endif - fd = open(filename, oflag, mode); - if (fd < 0) return -1; - - ks_rwl_write_lock(l->lock); - ks_list_dump_filedescriptor(l, fd, len); - ks_rwl_write_unlock(l->lock); - close(fd); - - return 0; -} - -int ks_list_restore_file(ks_list_t *restrict l, const char *restrict filename, ks_size_t *restrict len) { - int fd; - - fd = open(filename, O_RDONLY, 0); - if (fd < 0) return -1; - - ks_rwl_write_lock(l->lock); - ks_list_restore_filedescriptor(l, fd, len); - ks_rwl_write_unlock(l->lock); - close(fd); - - return 0; -} -#endif /* ifndef SIMCLIST_NO_DUMPRESTORE */ - - -static int ks_list_drop_elem(ks_list_t *restrict l, struct ks_list_entry_s *tmp, unsigned int pos) { - if (tmp == NULL) return -1; - - /* fix mid pointer. This is wrt the PRE situation */ - if (l->numels % 2) { /* now odd */ - /* sort out the base case by hand */ - if (l->numels == 1) l->mid = NULL; - else if (pos >= l->numels / 2) l->mid = l->mid->prev; - } - else { /* now even */ - if (pos < l->numels / 2) l->mid = l->mid->next; - } - - tmp->prev->next = tmp->next; - tmp->next->prev = tmp->prev; - - /* free what's to be freed */ - if (l->attrs.copy_data && tmp->data != NULL) - ks_pool_free(&tmp->data); - - if (l->spareelsnum < SIMCLIST_MAX_SPARE_ELEMS) { - l->spareels[l->spareelsnum++] = tmp; - } - else { - ks_pool_free(&tmp); - } - - return 0; -} - -/* ready-made comparators and meters */ -#define SIMCLIST_NUMBER_COMPARATOR(type) int ks_list_comparator_##type(const void *a, const void *b) { return( *(type *)a < *(type *)b) - (*(type *)a > *(type *)b); } - -SIMCLIST_NUMBER_COMPARATOR(int8_t) -SIMCLIST_NUMBER_COMPARATOR(int16_t) -SIMCLIST_NUMBER_COMPARATOR(int32_t) -SIMCLIST_NUMBER_COMPARATOR(int64_t) - -SIMCLIST_NUMBER_COMPARATOR(uint8_t) -SIMCLIST_NUMBER_COMPARATOR(uint16_t) -SIMCLIST_NUMBER_COMPARATOR(uint32_t) -SIMCLIST_NUMBER_COMPARATOR(uint64_t) - -SIMCLIST_NUMBER_COMPARATOR(float) -SIMCLIST_NUMBER_COMPARATOR(double) - -int ks_list_comparator_string(const void *a, const void *b) { return strcmp((const char *)b, (const char *)a); } - -/* ready-made metric functions */ -#define SIMCLIST_METER(type) ks_size_t ks_list_meter_##type(const void *el) { if (el) { /* kill compiler whinge */ } return sizeof(type); } - -SIMCLIST_METER(int8_t) -SIMCLIST_METER(int16_t) -SIMCLIST_METER(int32_t) -SIMCLIST_METER(int64_t) - -SIMCLIST_METER(uint8_t) -SIMCLIST_METER(uint16_t) -SIMCLIST_METER(uint32_t) -SIMCLIST_METER(uint64_t) - -SIMCLIST_METER(float) -SIMCLIST_METER(double) - -ks_size_t ks_list_meter_string(const void *el) { return strlen((const char *)el) + 1; } - -/* ready-made hashing functions */ -#define SIMCLIST_HASHCOMPUTER(type) ks_list_hash_t ks_list_hashcomputer_##type(const void *el) { return (ks_list_hash_t)(*(type *)el); } - -SIMCLIST_HASHCOMPUTER(int8_t) -SIMCLIST_HASHCOMPUTER(int16_t) -SIMCLIST_HASHCOMPUTER(int32_t) -SIMCLIST_HASHCOMPUTER(int64_t) - -SIMCLIST_HASHCOMPUTER(uint8_t) -SIMCLIST_HASHCOMPUTER(uint16_t) -SIMCLIST_HASHCOMPUTER(uint32_t) -SIMCLIST_HASHCOMPUTER(uint64_t) - -SIMCLIST_HASHCOMPUTER(float) -SIMCLIST_HASHCOMPUTER(double) - -ks_list_hash_t ks_list_hashcomputer_string(const void *el) { - ks_size_t l; - ks_list_hash_t hash = 123; - const char *str = (const char *)el; - char plus; - - for (l = 0; str[l] != '\0'; l++) { - if (l) plus = (char)(hash ^ str[l]); - else plus = (char)(hash ^ (str[l] - str[0])); - hash += (plus << (CHAR_BIT * (l % sizeof(ks_list_hash_t)))); - } - - return hash; -} - - -static int ks_list_repOk(const ks_list_t *restrict l) { - int ok, i; - struct ks_list_entry_s *s; - - ok = (l != NULL) && ( - /* head/tail checks */ - (l->head_sentinel != NULL && l->tail_sentinel != NULL) && - (l->head_sentinel != l->tail_sentinel) && (l->head_sentinel->prev == NULL && l->tail_sentinel->next == NULL) && - /* empty list */ - (l->numels > 0 || (l->mid == NULL && l->head_sentinel->next == l->tail_sentinel && l->tail_sentinel->prev == l->head_sentinel)) && - /* spare elements checks */ - l->spareelsnum <= SIMCLIST_MAX_SPARE_ELEMS - ); - - if (!ok) return 0; - - if (l->numels >= 1) { - /* correct referencing */ - for (i = -1, s = l->head_sentinel; i < (int)(l->numels - 1) / 2 && s->next != NULL; i++, s = s->next) { - if (s->next->prev != s) break; - } - ok = (i == (int)(l->numels - 1) / 2 && l->mid == s); - if (!ok) return 0; - for (; s->next != NULL; i++, s = s->next) { - if (s->next->prev != s) break; - } - ok = (i == (int)l->numels && s == l->tail_sentinel); - } - - return ok; -} - -static int ks_list_attrOk(const ks_list_t *restrict l) { - int ok; - - ok = (l->attrs.copy_data == 0 || l->attrs.meter != NULL); - return ok; -} - - -/* For Emacs: - * Local Variables: - * mode:c - * indent-tabs-mode:t - * tab-width:4 - * c-basic-offset:4 - * End: - * For VIM: - * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: - */ diff --git a/libs/libks/test/.gitignore b/libs/libks/test/.gitignore deleted file mode 100644 index a17940c85b..0000000000 --- a/libs/libks/test/.gitignore +++ /dev/null @@ -1,16 +0,0 @@ -*.log -*.trs -table_file -testpools -testtable -testthreadmutex -testtime -testhash -testq -testsock -testsock2 -testwebsock -testdht -testdht_net -testdht_msg -dht_example diff --git a/libs/libks/test/Makefile.am b/libs/libks/test/Makefile.am deleted file mode 100644 index 8d6e0843ec..0000000000 --- a/libs/libks/test/Makefile.am +++ /dev/null @@ -1,65 +0,0 @@ -AM_CFLAGS += -I$(abs_top_srcdir)/src/include -g -ggdb -O0 $(openssl_CFLAGS) -TEST_LDADD = $(abs_top_builddir)/libks.la $(openssl_LIBS) -check_PROGRAMS = - -EXTRA_DIST = tap.h - -check_PROGRAMS += testpools -testpools_SOURCES = testpools.c tap.c -testpools_CFLAGS = $(AM_CFLAGS) -testpools_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testrealloc -testrealloc_SOURCES = testrealloc.c tap.c -testrealloc_CFLAGS = $(AM_CFLAGS) -testrealloc_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testacl -testacl_SOURCES = testacl.c tap.c -testacl_CFLAGS = $(AM_CFLAGS) -testacl_LDADD = $(TEST_LDADD) - -check_PROGRAMS += test_thread_pools -test_thread_pools_SOURCES = test_thread_pools.c tap.c -test_thread_pools_CFLAGS = $(AM_CFLAGS) -test_thread_pools_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testthreadmutex -testthreadmutex_SOURCES = testthreadmutex.c tap.c -testthreadmutex_CFLAGS = $(AM_CFLAGS) -testthreadmutex_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testtime -testtime_SOURCES = testtime.c tap.c -testtime_CFLAGS = $(AM_CFLAGS) -testtime_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testq -testq_SOURCES = testq.c tap.c -testq_CFLAGS = $(AM_CFLAGS) -testq_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testhash -testhash_SOURCES = testhash.c tap.c -testhash_CFLAGS = $(AM_CFLAGS) -testhash_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testsock -testsock_SOURCES = testsock.c tap.c -testsock_CFLAGS = $(AM_CFLAGS) -testsock_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testsock2 -testsock2_SOURCES = testsock2.c tap.c -testsock2_CFLAGS = $(AM_CFLAGS) -testsock2_LDADD = $(TEST_LDADD) - -check_PROGRAMS += testwebsock -testwebsock_SOURCES = testwebsock.c tap.c -testwebsock_CFLAGS = $(AM_CFLAGS) -testwebsock_LDADD = $(TEST_LDADD) - - -TESTS=$(check_PROGRAMS) - -tests: $(check_PROGRAMS) diff --git a/libs/libks/test/tap.c b/libs/libks/test/tap.c deleted file mode 100644 index 152e39e8e0..0000000000 --- a/libs/libks/test/tap.c +++ /dev/null @@ -1,354 +0,0 @@ -/* -libtap - Write tests in C -Copyright 2012 Jake Gelbman -This file is licensed under the LGPL -*/ - -#define _DEFAULT_SOURCE 1 - -#include -#include -#include -#include -#include "tap.h" - -static int expected_tests = NO_PLAN; -static int failed_tests; -static int current_test; -static char *todo_mesg; - -static char * -vstrdupf (const char *fmt, va_list args) { - char *str; - int size; - va_list args2; - va_copy(args2, args); - if (!fmt) - fmt = ""; - size = vsnprintf(NULL, 0, fmt, args2) + 2; - str = malloc(size); - if (!str) { - perror("malloc error"); - exit(1); - } - vsprintf(str, fmt, args); - va_end(args2); - return str; -} - -void -tap_plan (int tests, const char *fmt, ...) { - expected_tests = tests; - if (tests == SKIP_ALL) { - char *why; - va_list args; - va_start(args, fmt); - why = vstrdupf(fmt, args); - va_end(args); - printf("1..0 "); - diag("SKIP %s\n", why); - exit(0); - } - if (tests != NO_PLAN) { - printf("1..%d\n", tests); - } -} - -int -vok_at_loc (const char *file, int line, int test, const char *fmt, - va_list args) -{ - char *name = vstrdupf(fmt, args); - if (!test) { - printf("not "); - } - printf("ok %d", ++current_test); - if (*name) - printf(" - %s", name); - if (todo_mesg) { - printf(" # TODO"); - if (*todo_mesg) - printf(" %s", todo_mesg); - } - printf("\n"); - if (!test) { - printf("# Failed "); - if (todo_mesg) - printf("(TODO) "); - printf("test "); - if (*name) - printf("'%s'\n# ", name); - printf("at %s line %d.\n", file, line); - if (!todo_mesg) - failed_tests++; - } - free(name); - return test; -} - -int -ok_at_loc (const char *file, int line, int test, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - return test; -} - -static int -mystrcmp (const char *a, const char *b) { - return a == b ? 0 : !a ? -1 : !b ? 1 : strcmp(a, b); -} - -#define eq(a, b) (!mystrcmp(a, b)) -#define ne(a, b) (mystrcmp(a, b)) - -int -is_at_loc (const char *file, int line, const char *got, const char *expected, - const char *fmt, ...) -{ - int test = eq(got, expected); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" got: '%s'", got); - diag(" expected: '%s'", expected); - } - return test; -} - -int -isnt_at_loc (const char *file, int line, const char *got, const char *expected, - const char *fmt, ...) -{ - int test = ne(got, expected); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" got: '%s'", got); - diag(" expected: anything else"); - } - return test; -} - -int -cmp_ok_at_loc (const char *file, int line, int a, const char *op, int b, - const char *fmt, ...) -{ - int test = eq(op, "||") ? a || b - : eq(op, "&&") ? a && b - : eq(op, "|") ? a | b - : eq(op, "^") ? a ^ b - : eq(op, "&") ? a & b - : eq(op, "==") ? a == b - : eq(op, "!=") ? a != b - : eq(op, "<") ? a < b - : eq(op, ">") ? a > b - : eq(op, "<=") ? a <= b - : eq(op, ">=") ? a >= b - : eq(op, "<<") ? a << b - : eq(op, ">>") ? a >> b - : eq(op, "+") ? a + b - : eq(op, "-") ? a - b - : eq(op, "*") ? a * b - : eq(op, "/") ? a / b - : eq(op, "%") ? a % b - : diag("unrecognized operator '%s'", op); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - diag(" %d", a); - diag(" %s", op); - diag(" %d", b); - } - return test; -} - -static int -find_mem_diff (const char *a, const char *b, size_t n, size_t *offset) { - size_t i; - if (a == b) - return 0; - if (!a || !b) - return 2; - for (i = 0; i < n; i++) { - if (a[i] != b[i]) { - *offset = i; - return 1; - } - } - return 0; -} - -int -cmp_mem_at_loc (const char *file, int line, const void *got, - const void *expected, size_t n, const char *fmt, ...) -{ - size_t offset; - int diff = find_mem_diff(got, expected, n, &offset); - va_list args; - va_start(args, fmt); - vok_at_loc(file, line, !diff, fmt, args); - va_end(args); - if (diff == 1) { - diag(" Difference starts at offset %d", offset); - diag(" got: 0x%02x", ((unsigned char *)got)[offset]); - diag(" expected: 0x%02x", ((unsigned char *)expected)[offset]); - } - else if (diff == 2) { - diag(" got: %s", got ? "not NULL" : "NULL"); - diag(" expected: %s", expected ? "not NULL" : "NULL"); - } - return !diff; -} - -int -diag (const char *fmt, ...) { - va_list args; - char *mesg, *line; - int i; - va_start(args, fmt); - if (!fmt) - return 0; - mesg = vstrdupf(fmt, args); - line = mesg; - for (i = 0; *line; i++) { - char c = mesg[i]; - if (!c || c == '\n') { - mesg[i] = '\0'; - printf("# %s\n", line); - if (!c) - break; - mesg[i] = c; - line = mesg + i + 1; - } - } - free(mesg); - va_end(args); - return 0; -} - -int -exit_status () { - int retval = 0; - if (expected_tests == NO_PLAN) { - printf("1..%d\n", current_test); - } - else if (current_test != expected_tests) { - diag("Looks like you planned %d test%s but ran %d.", - expected_tests, expected_tests > 1 ? "s" : "", current_test); - retval = 2; - } - if (failed_tests) { - diag("Looks like you failed %d test%s of %d run.", - failed_tests, failed_tests > 1 ? "s" : "", current_test); - retval = 1; - } - return retval; -} - -int -bail_out (int ignore, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - printf("Bail out! "); - vprintf(fmt, args); - printf("\n"); - va_end(args); - exit(255); - return 0; -} - -void -tap_skip (int n, const char *fmt, ...) { - char *why; - va_list args; - va_start(args, fmt); - why = vstrdupf(fmt, args); - va_end(args); - while (n --> 0) { - printf("ok %d ", ++current_test); - diag("skip %s\n", why); - } - free(why); -} - -void -tap_todo (int ignore, const char *fmt, ...) { - va_list args; - va_start(args, fmt); - todo_mesg = vstrdupf(fmt, args); - va_end(args); -} - -void -tap_end_todo () { - free(todo_mesg); - todo_mesg = NULL; -} - -#ifndef _WIN32 -#include -#include -#include - -#if defined __APPLE__ || defined BSD -#define MAP_ANONYMOUS MAP_ANON -#endif - -/* Create a shared memory int to keep track of whether a piece of code executed -dies. to be used in the dies_ok and lives_ok macros. */ -int -tap_test_died (int status) { - static int *test_died = NULL; - int prev; - if (!test_died) { - test_died = mmap(0, sizeof (int), PROT_READ | PROT_WRITE, - MAP_SHARED | MAP_ANONYMOUS, -1, 0); - *test_died = 0; - } - prev = *test_died; - *test_died = status; - return prev; -} - -int -like_at_loc (int for_match, const char *file, int line, const char *got, - const char *expected, const char *fmt, ...) -{ - int test; - regex_t re; - va_list args; - int err = regcomp(&re, expected, REG_EXTENDED); - if (err) { - char errbuf[256]; - regerror(err, &re, errbuf, sizeof errbuf); - fprintf(stderr, "Unable to compile regex '%s': %s at %s line %d\n", - expected, errbuf, file, line); - exit(255); - } - err = regexec(&re, got, 0, NULL, 0); - regfree(&re); - test = for_match ? !err : err; - va_start(args, fmt); - vok_at_loc(file, line, test, fmt, args); - va_end(args); - if (!test) { - if (for_match) { - diag(" '%s'", got); - diag(" doesn't match: '%s'", expected); - } - else { - diag(" '%s'", got); - diag(" matches: '%s'", expected); - } - } - return test; -} -#endif diff --git a/libs/libks/test/tap.h b/libs/libks/test/tap.h deleted file mode 100644 index 8269e7ead7..0000000000 --- a/libs/libks/test/tap.h +++ /dev/null @@ -1,115 +0,0 @@ -/* -libtap - Write tests in C -Copyright 2012 Jake Gelbman -This file is licensed under the LGPL -*/ - -#ifndef __TAP_H__ -#define __TAP_H__ - -#ifdef __cplusplus -extern "C" { -#endif - -#ifndef va_copy -#ifdef __va_copy -#define va_copy __va_copy -#else -#define va_copy(d, s) ((d) = (s)) -#endif -#endif - -#include -#include -#include - -int vok_at_loc (const char *file, int line, int test, const char *fmt, - va_list args); -int ok_at_loc (const char *file, int line, int test, const char *fmt, - ...); -int is_at_loc (const char *file, int line, const char *got, - const char *expected, const char *fmt, ...); -int isnt_at_loc (const char *file, int line, const char *got, - const char *expected, const char *fmt, ...); -int cmp_ok_at_loc (const char *file, int line, int a, const char *op, - int b, const char *fmt, ...); -int cmp_mem_at_loc (const char *file, int line, const void *got, - const void *expected, size_t n, const char *fmt, ...); -int bail_out (int ignore, const char *fmt, ...); -void tap_plan (int tests, const char *fmt, ...); -int diag (const char *fmt, ...); -int exit_status (void); -void tap_skip (int n, const char *fmt, ...); -void tap_todo (int ignore, const char *fmt, ...); -void tap_end_todo (void); - -#define NO_PLAN -1 -#define SKIP_ALL -2 -#define ok(...) ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define is(...) is_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define isnt(...) isnt_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define cmp_ok(...) cmp_ok_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL) -#define cmp_mem(...) cmp_mem_at_loc(__FILE__, __LINE__, __VA_ARGS__, NULL); -#define plan(...) tap_plan(__VA_ARGS__, NULL) -#define done_testing() return exit_status() -#define BAIL_OUT(...) bail_out(0, "" __VA_ARGS__, NULL) -#define pass(...) ok(1, "" __VA_ARGS__) -#define fail(...) ok(0, "" __VA_ARGS__) - -#define skip(test, ...) do {if (test) {tap_skip(__VA_ARGS__, NULL); break;} -#define end_skip } while (0) - -#define todo(...) tap_todo(0, "" __VA_ARGS__, NULL) -#define end_todo tap_end_todo() - -#define dies_ok(...) dies_ok_common(1, __VA_ARGS__) -#define lives_ok(...) dies_ok_common(0, __VA_ARGS__) - -#ifdef _WIN32 -#define like(...) tap_skip(1, "like is not implemented on Windows") -#define unlike tap_skip(1, "unlike is not implemented on Windows") -#define dies_ok_common(...) \ - tap_skip(1, "Death detection is not supported on Windows") -#else -#define like(...) like_at_loc(1, __FILE__, __LINE__, __VA_ARGS__, NULL) -#define unlike(...) like_at_loc(0, __FILE__, __LINE__, __VA_ARGS__, NULL) -int like_at_loc (int for_match, const char *file, int line, - const char *got, const char *expected, - const char *fmt, ...); -#include -#include -#include -int tap_test_died (int status); -#define dies_ok_common(for_death, code, ...) \ - do { \ - int cpid; \ - int it_died; \ - tap_test_died(1); \ - cpid = fork(); \ - switch (cpid) { \ - case -1: \ - perror("fork error"); \ - exit(1); \ - case 0: \ - close(1); \ - close(2); \ - code \ - tap_test_died(0); \ - exit(0); \ - } \ - if (waitpid(cpid, NULL, 0) < 0) { \ - perror("waitpid error"); \ - exit(1); \ - } \ - it_died = tap_test_died(0); \ - if (!it_died) \ - {code} \ - ok(for_death ? it_died : !it_died, "" __VA_ARGS__); \ - } while (0) -#endif - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/libs/libks/test/test_thread_pools.c b/libs/libks/test/test_thread_pools.c deleted file mode 100644 index d3af3db16f..0000000000 --- a/libs/libks/test/test_thread_pools.c +++ /dev/null @@ -1,71 +0,0 @@ -#include "ks.h" - -#include -#include -#include -#include "tap.h" - -typedef struct ks_dht_nodeid_s { uint8_t id[20]; } ks_dht_nodeid_t; - -struct x { - int i; - ks_pool_t *pool; -}; - -static void *test1_thread(ks_thread_t *thread, void *data) -{ - struct x *mydata = (struct x *) data; - - ks_log(KS_LOG_DEBUG, "Thread %d\n", mydata->i); - ks_sleep(100000); - ks_pool_free(&mydata); - return NULL; -} - -static int test1() -{ - ks_pool_t *pool; - ks_thread_pool_t *tp = NULL; - int i = 0; - - ks_pool_open(&pool); - - ks_thread_pool_create(&tp, 2, 10, KS_THREAD_DEFAULT_STACK, KS_PRI_NORMAL, 5); - - - for (i = 0; i < 500; i++) { - struct x *data = ks_pool_alloc(pool, sizeof(*data)); - data->i = i; - data->pool = pool; - ks_sleep(1); - ks_thread_pool_add_job(tp, test1_thread, data); - } - - - while(ks_thread_pool_backlog(tp)) { - ks_sleep(100000); - } - - ks_sleep(10000000); - - ks_thread_pool_destroy(&tp); - ks_pool_close(&pool); - - return 1; -} - -int main(int argc, char **argv) -{ - - - ks_init(); - ks_global_set_default_logger(7); - - plan(1); - - ok(test1()); - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/test_thread_pools.vcxproj b/libs/libks/test/test_thread_pools.vcxproj deleted file mode 100644 index f6f82fc689..0000000000 --- a/libs/libks/test/test_thread_pools.vcxproj +++ /dev/null @@ -1,194 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {8AFFECE6-2A0B-4D44-990C-6D3DD832A250} - Win32Proj - test_thread_pools - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testacl.c b/libs/libks/test/testacl.c deleted file mode 100644 index d676f2ce55..0000000000 --- a/libs/libks/test/testacl.c +++ /dev/null @@ -1,70 +0,0 @@ -#include "ks.h" - -#include -#include -#include -#include "tap.h" - -int main(int argc, char **argv) -{ - ks_pool_t *pool; - ks_network_list_t *list = NULL; - ks_bool_t match; - - ks_init(); - - plan(8); - - ks_pool_open(&pool); - - ks_network_list_create(&list, "test", KS_FALSE, pool); - - - ks_network_list_add_cidr(list, "10.0.0.0/8", KS_TRUE); - ks_network_list_add_cidr(list, "172.16.0.0/12", KS_TRUE); - ks_network_list_add_cidr(list, "192.168.0.0/16", KS_TRUE); - ks_network_list_add_cidr(list, "fe80::/10", KS_TRUE); - - - match = ks_check_network_list_ip("192.168.1.1", list); - ok(match); - - match = ks_check_network_list_ip("208.34.128.7", list); - ok (!match); - - match = ks_check_network_list_ip_cidr("192.168.1.1", "192.168.0.0/16"); - ok(match); - - match = ks_check_network_list_ip_cidr("208.34.128.7", "192.168.0.0/16"); - ok (!match); - - - ks_pool_free(&list); - - - ks_network_list_create(&list, "test", KS_TRUE, pool); - - ks_network_list_add_cidr(list, "0.0.0.0/0", KS_FALSE); - ks_network_list_add_cidr(list, "fe80::/10", KS_FALSE); - - - match = ks_check_network_list_ip("2637:f368:1281::10", list); - ok(match); - - match = ks_check_network_list_ip("fe80::18b7:53b3:51d8:f5cf", list); - ok(!match); - - match = ks_check_network_list_ip_cidr("fe80::18b7:53b3:51d8:f5cf", "fe80::/10"); - ok(match); - - match = ks_check_network_list_ip_cidr("2637:f368:1281::10", "fe80::/10"); - ok(!match); - - ks_pool_free(&list); - - ks_pool_close(&pool); - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testacl.vcxproj b/libs/libks/test/testacl.vcxproj deleted file mode 100644 index 0b0c732c2b..0000000000 --- a/libs/libks/test/testacl.vcxproj +++ /dev/null @@ -1,193 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {1E6DE729-F4D4-4455-B64C-73B31C17E12C} - Win32Proj - testacl - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testhash.c b/libs/libks/test/testhash.c deleted file mode 100644 index 7c7589a740..0000000000 --- a/libs/libks/test/testhash.c +++ /dev/null @@ -1,181 +0,0 @@ -#include "ks.h" -#include "tap.h" - -int test1(void) -{ - ks_pool_t *pool; - ks_hash_t *hash; - int i, sum1 = 0, sum2 = 0; - - ks_pool_open(&pool); - ks_hash_create(&hash, KS_HASH_MODE_DEFAULT, KS_HASH_FREE_BOTH | KS_HASH_FLAG_RWLOCK, pool); - - for (i = 1; i < 1001; i++) { - char *key = ks_pprintf(pool, "KEY %d", i); - char *val = ks_pprintf(pool, "%d", i); - ks_hash_insert(hash, key, val); - sum1 += i; - } - - - - ks_hash_iterator_t *itt; - - ks_hash_write_lock(hash); - for (itt = ks_hash_first(hash, KS_UNLOCKED); itt; ) { - const void *key; - void *val; - - ks_hash_this(itt, &key, NULL, &val); - - printf("%s=%s\n", (char *)key, (char *)val); - sum2 += atoi(val); - - itt = ks_hash_next(&itt); - ks_hash_remove(hash, (char *)key); - } - ks_hash_write_unlock(hash); - - ks_hash_destroy(&hash); - - ks_pool_close(&pool); - - return (sum1 == sum2); -} - -#define MAX 100 - -static void *test2_thread(ks_thread_t *thread, void *data) -{ - ks_hash_iterator_t *itt; - ks_hash_t *hash = (ks_hash_t *) data; - - while(KS_THREAD_IS_RUNNING(thread)) { - for (itt = ks_hash_first(hash, KS_READLOCKED); itt; itt = ks_hash_next(&itt)) { - const void *key; - void *val; - - ks_hash_this(itt, &key, NULL, &val); - - printf("%u ITT %s=%s\n", (int)ks_thread_self_id(), (char *)key, (char *)val); - } - ks_sleep(100000); - } - - - return NULL; -} - -int test2(void) -{ - ks_thread_t *threads[MAX]; - int ttl = 5; - int runs = 5; - ks_pool_t *pool; - ks_hash_t *hash; - int i; - ks_hash_iterator_t *itt; - - ks_pool_open(&pool); - ks_hash_create(&hash, KS_HASH_MODE_DEFAULT, KS_HASH_FREE_BOTH | KS_HASH_FLAG_RWLOCK, pool); - - for (i = 0; i < ttl; i++) { - ks_thread_create(&threads[i], test2_thread, hash, pool); - } - - for(i = 0; i < runs; i++) { - int x = rand() % 5; - int j; - - for (j = 0; j < 100; j++) { - char *key = ks_pprintf(pool, "KEY %d", j); - char *val = ks_pprintf(pool, "%d", j); - ks_hash_insert(hash, key, val); - } - - ks_sleep(x * 1000000); - - ks_hash_write_lock(hash); - for (itt = ks_hash_first(hash, KS_UNLOCKED); itt; ) { - const void *key; - void *val; - - ks_hash_this(itt, &key, NULL, &val); - - printf("DEL %s=%s\n", (char *)key, (char *)val); - - itt = ks_hash_next(&itt); - ks_hash_remove(hash, (char *)key); - } - ks_hash_write_unlock(hash); - - } - - for (i = 0; i < ttl; i++) { - threads[i]->state = KS_THREAD_SHUTDOWN; - ks_thread_join(threads[i]); - } - - - ks_hash_destroy(&hash); - ks_pool_close(&pool); - - return 1; -} - -//#include "sodium.h" -#define TEST3_SIZE 20 -int test3(void) -{ - ks_pool_t *pool; - ks_hash_t *hash; - ks_byte_t data[TEST3_SIZE]; - ks_byte_t data2[TEST3_SIZE]; - ks_byte_t data3[TEST3_SIZE]; - char *A, *B, *C; - - ks_pool_open(&pool); - ks_hash_create(&hash, KS_HASH_MODE_ARBITRARY, KS_HASH_FLAG_NOLOCK, pool); - ks_hash_set_keysize(hash, TEST3_SIZE); - - ks_rng_get_data(data, sizeof(data)); - ks_rng_get_data(data2, sizeof(data)); - //randombytes_buf(data, sizeof(data)); - //randombytes_buf(data2, sizeof(data2)); - - ks_hash_insert(hash, data, "FOO"); - ks_hash_insert(hash, data2, "BAR"); - ks_hash_insert(hash, data3, "BAZ"); - - - A = (char *)ks_hash_search(hash, data, KS_UNLOCKED); - B = (char *)ks_hash_search(hash, data2, KS_UNLOCKED); - C = (char *)ks_hash_search(hash, data3, KS_UNLOCKED); - - - printf("RESULT [%s][%s][%s]\n", A, B, C); - - ks_hash_destroy(&hash); - - ks_pool_close(&pool); - - return !strcmp(A, "FOO") && !strcmp(B, "BAR") && !strcmp(C, "BAZ"); - -} - - -int main(int argc, char **argv) -{ - - ks_init(); - - plan(3); - - ok(test1()); - ok(test2()); - ok(test3()); - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testhash.vcxproj b/libs/libks/test/testhash.vcxproj deleted file mode 100644 index 877b197fd8..0000000000 --- a/libs/libks/test/testhash.vcxproj +++ /dev/null @@ -1,189 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {43724CF4-FCE1-44FE-AB36-C86E3979B350} - Win32Proj - testhash - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - false - - - Console - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testpolling.c b/libs/libks/test/testpolling.c deleted file mode 100644 index 6e7b96ea0c..0000000000 --- a/libs/libks/test/testpolling.c +++ /dev/null @@ -1,115 +0,0 @@ -#include "ks.h" - -#include -#include -#include -#include "tap.h" - -ks_socket_t start_listen(ks_sockaddr_t *addr) -{ - ks_socket_t listener = KS_SOCK_INVALID; - ks_status_t ret = KS_STATUS_SUCCESS; - - ks_assert(addr); - - if ((listener = socket(addr->family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) { - ks_log(KS_LOG_DEBUG, "listener == KS_SOCK_INVALID\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - ks_socket_option(listener, SO_REUSEADDR, KS_TRUE); - ks_socket_option(listener, TCP_NODELAY, KS_TRUE); - if (addr->family == AF_INET6) ks_socket_option(listener, IPV6_V6ONLY, KS_TRUE); - - if (ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS) { - ks_log(KS_LOG_DEBUG, "ks_addr_bind(listener, addr) != KS_STATUS_SUCCESS\n"); - ret = KS_STATUS_FAIL; - goto done; - } - - if (listen(listener, 4) != 0) { - ks_log(KS_LOG_DEBUG, "listen(listener, backlog) != 0\n"); - ret = KS_STATUS_FAIL; - goto done; - } - -done: - if (ret != KS_STATUS_SUCCESS) { - if (listener != KS_SOCK_INVALID) { - ks_socket_shutdown(listener, SHUT_RDWR); - ks_socket_close(&listener); - listener = KS_SOCK_INVALID; - } - } - return listener; -} - -int main(int argc, char **argv) -{ - ks_pool_t *pool = NULL; - struct pollfd *listeners_poll = NULL; - int32_t listeners_count = 0; - int32_t listener_index = -1; - ks_sockaddr_t addr; - ks_socket_t listener = KS_SOCK_INVALID; - ks_socket_t sock = KS_SOCK_INVALID; - - ks_init(); - - plan(2); - - ks_pool_open(&pool); - - ks_addr_set(&addr, "0.0.0.0", 1234, AF_INET); - - listener = start_listen(&addr); - listener_index = listeners_count++; - listeners_poll = (struct pollfd *)ks_pool_alloc(pool, sizeof(struct pollfd) * listeners_count); - ok(listeners_poll != NULL); - - listeners_poll[listener_index].fd = listener; - listeners_poll[listener_index].events = POLLIN; - - while (1) { - int p = ks_poll(listeners_poll, listeners_count, 100); - if (p > 0) { - printf("POLL event occurred\n"); - for (int32_t index = 0; index < listeners_count; ++index) { - if (listeners_poll[index].revents & POLLERR) { - printf("POLLERR on index %d\n", index); - break; - } - if (!(listeners_poll[index].revents & POLLIN)) continue; - - printf("POLLIN on index %d\n", index); - - if ((sock = accept(listeners_poll[index].fd, NULL, NULL)) == KS_SOCK_INVALID) { - printf("Accept failed on index %d\n", index); - continue; - } - - printf("Accept success on index %d\n", index); - } - break; - } else if (p < 0) { - printf("Polling socket error %d\n", WSAGetLastError()); - } - } - - ok(sock != KS_SOCK_INVALID); - - if (sock != KS_SOCK_INVALID) ks_socket_close(&sock); - - for (int index = 0; index < listeners_count; ++index) { - listener = listeners_poll[index].fd; - ks_socket_close(&listener); - } - ks_pool_free(&listeners_poll); - - ks_pool_close(&pool); - - ks_shutdown(); - - done_testing(); -} \ No newline at end of file diff --git a/libs/libks/test/testpolling.vcxproj b/libs/libks/test/testpolling.vcxproj deleted file mode 100644 index 803359b394..0000000000 --- a/libs/libks/test/testpolling.vcxproj +++ /dev/null @@ -1,193 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {699A44BF-D03D-469F-83B2-C52C0B4B95BD} - Win32Proj - testpolling - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testpools.c b/libs/libks/test/testpools.c deleted file mode 100644 index 37dae04c38..0000000000 --- a/libs/libks/test/testpools.c +++ /dev/null @@ -1,260 +0,0 @@ -#include "ks.h" - -#include -#include -#include -#include "tap.h" -#define STR "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - -static void fill(char *str, int bytes, char c) -{ - memset(str, c, bytes -1); - *(str+(bytes-1)) = '\0'; -} - -struct foo { - int x; - char *str; -}; - - -void cleanup(void *ptr, void *arg, ks_pool_cleanup_action_t action, ks_pool_cleanup_type_t type) -{ - struct foo *foo = (struct foo *) ptr; - - printf("Cleanup %p action: %d\n", ptr, action); - - switch(action) { - case KS_MPCL_ANNOUNCE: - break; - case KS_MPCL_TEARDOWN: - break; - case KS_MPCL_DESTROY: - printf("DESTROY STR [%s]\n", foo->str); - free(foo->str); - foo->str = NULL; - } -} - - - -int main(int argc, char **argv) -{ - ks_pool_t *pool; - int err = 0; - char *str = NULL; - int bytes = 1024; - ks_status_t status; - struct foo *foo; - - ks_init(); - - plan(14); - - if (argc > 1) { - int tmp = atoi(argv[1]); - - if (tmp > 0) { - bytes = tmp; - } else { - fprintf(stderr, "INVALID\n"); - exit(255); - } - } - - - status = ks_pool_open(&pool); - - void *blah = ks_pool_alloc(pool, 64 * 1024); - - ks_pool_free(&blah); - - blah = ks_pool_alloc(pool, 2 * 1024); - - ks_pool_close(&pool); - - status = ks_pool_open(&pool); - - printf("OPEN: %p\n", (void *)pool); - ok(status == KS_STATUS_SUCCESS); - if (status != KS_STATUS_SUCCESS) { - fprintf(stderr, "OPEN ERR: %d [%s]\n", err, ks_pool_strerror(status)); - exit(255); - } - - printf("ALLOC:\n"); - str = ks_pool_alloc(pool, bytes); - - ok(str != NULL); - if (!str) { - fprintf(stderr, "ALLOC ERR\n"); - exit(255); - } - - fill(str, bytes, '.'); - printf("%s\n", str); - - printf("FREE:\n"); - - status = ks_pool_free(&str); - if (status != KS_STATUS_SUCCESS) { - fprintf(stderr, "FREE ERR: [%s]\n", ks_pool_strerror(err)); - exit(255); - } - - printf("ALLOC2:\n"); - - str = ks_pool_alloc(pool, bytes); - - ok(str != NULL); - if (!str) { - fprintf(stderr, "ALLOC2 ERR: [FAILED]\n"); - exit(255); - } - - - ks_snprintf(str, bytes, "%s", STR); - printf("%s\n", str); - - - printf("ALLOC3 (refs):\n"); - - str = ks_pool_ref(str); - - printf("STR [%s]\n", str); - - ks_pool_free(&str); - - ok(str != NULL && !strcmp(str, STR)); - - printf("STR [%s]\n", str); - - ks_pool_free(&str); - - ok(str == NULL); - - str = ks_pool_alloc(pool, bytes); - - ok(str != NULL); - if (!str) { - fprintf(stderr, "ALLOC2 ERR: [FAILED]\n"); - exit(255); - } - - fill(str, bytes, '-'); - printf("%s\n", str); - - printf("ALLOC OBJ:\n"); - - foo = ks_pool_alloc(pool, sizeof(struct foo)); - - ok(foo != NULL); - if (!foo) { - fprintf(stderr, "ALLOC OBJ: [FAILED]\n"); - exit(255); - } else { - printf("ALLOC OBJ [%p]:\n", (void *) foo); - } - - foo->x = 12; - foo->str = strdup("This is a test 1234 abcd; This will be called on explicit free\n"); - ks_pool_set_cleanup(foo, NULL, cleanup); - - printf("FREE OBJ:\n"); - - status = ks_pool_free(&foo); - ok(status == KS_STATUS_SUCCESS); - if (status != KS_STATUS_SUCCESS) { - fprintf(stderr, "FREE OBJ ERR: [%s]\n", ks_pool_strerror(status)); - exit(255); - } - - - printf("ALLOC OBJ2:\n"); - - foo = ks_pool_alloc(pool, sizeof(struct foo)); - - ok(foo != NULL); - if (!foo) { - fprintf(stderr, "ALLOC OBJ2: [FAILED]\n"); - exit(255); - } else { - printf("ALLOC OBJ2 [%p]:\n", (void *) foo); - } - - foo->x = 12; - foo->str = strdup("This is a second test 1234 abcd; This will be called on pool clear/destroy\n"); - ks_pool_set_cleanup(foo, NULL, cleanup); - - - printf("ALLOC OBJ3: %p\n", (void *)pool); - - foo = ks_pool_alloc(pool, sizeof(struct foo)); - - ok(foo != NULL); - if (!foo) { - fprintf(stderr, "ALLOC OBJ3: [FAILED]\n"); - exit(255); - } else { - printf("ALLOC OBJ3 [%p]:\n", (void *) foo); - } - - printf("CLEANUP: %p\n", (void *)pool); - foo->x = 12; - foo->str = strdup("This is a third test 1234 abcd; This will be called on pool clear/destroy\n"); - ks_pool_set_cleanup(foo, NULL, cleanup); - - - - printf("RESIZE: %p\n", (void *)pool); - - - ks_snprintf(str, bytes, "%s", STR); - printf("1 STR [%s]\n", str); - bytes *= 2; - str = ks_pool_resize(str, bytes); - printf("2 STR [%s]\n", str); - - ok(!strcmp(str, STR)); - - if (!str) { - fprintf(stderr, "RESIZE ERR: [FAILED]\n"); - exit(255); - } - - fill(str, bytes, '*'); - printf("%s\n", str); - - - printf("FREE 2:\n"); - - status = ks_pool_free(&str); - ok(status == KS_STATUS_SUCCESS); - if (status != KS_STATUS_SUCCESS) { - fprintf(stderr, "FREE2 ERR: [%s]\n", ks_pool_strerror(status)); - exit(255); - } - - - printf("CLEAR:\n"); - status = ks_pool_clear(pool); - - ok(status == KS_STATUS_SUCCESS); - if (status != KS_STATUS_SUCCESS) { - fprintf(stderr, "CLEAR ERR: [%s]\n", ks_pool_strerror(status)); - exit(255); - } - - printf("CLOSE:\n"); - status = ks_pool_close(&pool); - - ok(status == KS_STATUS_SUCCESS); - if (status != KS_STATUS_SUCCESS) { - fprintf(stderr, "CLOSE ERR: [%s]\n", ks_pool_strerror(err)); - exit(255); - } - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testpools.vcxproj b/libs/libks/test/testpools.vcxproj deleted file mode 100644 index 1755d27d1f..0000000000 --- a/libs/libks/test/testpools.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {5825A3B2-31A0-475A-AF32-44FB0D8B52D4} - Win32Proj - testpools - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testq.c b/libs/libks/test/testq.c deleted file mode 100644 index e79c5ba6ab..0000000000 --- a/libs/libks/test/testq.c +++ /dev/null @@ -1,225 +0,0 @@ -#include "ks.h" -#include "tap.h" -#define MAX 200 - -static void *test1_thread(ks_thread_t *thread, void *data) -{ - ks_q_t *q = (ks_q_t *) data; - void *pop; - - while(ks_q_pop(q, &pop) == KS_STATUS_SUCCESS) { - //int *i = (int *)pop; - //printf("POP %d\n", *i); - ks_pool_free(&pop); - } - - return NULL; -} - -static void do_flush(ks_q_t *q, void *ptr, void *flush_data) -{ - //ks_pool_t *pool = (ks_pool_t *)flush_data; - ks_pool_free(&ptr); - -} - -int qtest1(int loops) -{ - ks_thread_t *thread; - ks_q_t *q; - ks_pool_t *pool; - int i; - int r = 1; - void *pop; - - ks_pool_open(&pool); - ks_q_create(&q, pool, loops); - - ks_thread_create(&thread, test1_thread, q, pool); - - if (ks_q_pop_timeout(q, &pop, 500) != KS_STATUS_TIMEOUT) { - r = 0; - goto end; - } - - for (i = 0; i < 10000; i++) { - int *val = (int *)ks_pool_alloc(pool, sizeof(int)); - *val = i; - ks_q_push(q, val); - } - - ks_q_wait(q); - - ks_q_term(q); - ks_thread_join(thread); - - ks_q_destroy(&q); - - ks_q_create(&q, pool, loops); - ks_q_set_flush_fn(q, do_flush, pool); - - for (i = 0; i < loops; i++) { - int *val = (int *)ks_pool_alloc(pool, sizeof(int)); - *val = i; - ks_q_push(q, val); - } - - end: - - ks_q_destroy(&q); - - ks_pool_close(&pool); - - return r; - -} - -struct test2_data { - ks_q_t *q; - int try; - int ready; - int running; -}; - -static void *test2_thread(ks_thread_t *thread, void *data) -{ - struct test2_data *t2 = (struct test2_data *) data; - void *pop; - ks_status_t status; - int popped = 0; - - while (t2->running && (t2->try && !t2->ready)) { - ks_sleep(10000); - continue; - } - - while (t2->running || ks_q_size(t2->q)) { - if (t2->try) { - status = ks_q_trypop(t2->q, &pop); - } else { - status = ks_q_pop(t2->q, &pop); - } - - if (status == KS_STATUS_SUCCESS) { - //int *i = (int *)pop; - //printf("%p POP %d\n", (void *)pthread_self(), *i); - popped++; - ks_pool_free(&pop); - } else if (status == KS_STATUS_INACTIVE) { - break; - } else if (t2->try && ks_q_size(t2->q)) { - int s = rand() % 100; - ks_sleep(s * 1000); - } - } - - return (void *) (intptr_t)popped; -} - -ks_size_t qtest2(int ttl, int try, int loops) -{ - ks_thread_t *threads[MAX]; - ks_q_t *q; - ks_pool_t *pool; - int i; - struct test2_data t2 = { 0 }; - ks_size_t r; - int dropped = 0; - int qlen = loops / 2; - int total_popped = 0; - - ks_pool_open(&pool); - ks_q_create(&q, pool, qlen); - - t2.q = q; - t2.try = try; - t2.running = 1; - - for (i = 0; i < ttl; i++) { - ks_thread_create(&threads[i], test2_thread, &t2, pool); - } - - //ks_sleep(loops00); - - for (i = 0; i < loops; i++) { - int *val = (int *)ks_pool_alloc(pool, sizeof(int)); - *val = i; - if (try > 1) { - if (ks_q_trypush(q, val) != KS_STATUS_SUCCESS) { - dropped++; - } - } else { - ks_q_push(q, val); - } - if (i > qlen / 2) { - t2.ready = 1; - } - } - - t2.running = 0; - - if (!try) { - ks_q_wait(q); - ks_q_term(q); - } - - for (i = 0; i < ttl; i++) { - int popped; - ks_thread_join(threads[i]); - popped = (int)(intptr_t)threads[i]->return_data; - if (popped) { - printf("%d/%d POPPED %d\n", i, ttl, popped); - } - total_popped += popped; - } - - r = ks_q_size(q); - ks_assert(r == 0); - - ks_q_destroy(&q); - - - - printf("TOTAL POPPED: %d DROPPED %d SUM: %d\n", total_popped, dropped, total_popped + dropped);fflush(stdout); - - if (try < 2) { - ks_assert(total_popped == loops); - } else { - ks_assert(total_popped + dropped == loops); - } - - ks_pool_close(&pool); - - return r; - -} - - -int main(int argc, char **argv) -{ - int ttl; - int size = 100000; - int runs = 1; - int i; - - ks_init(); - - plan(4 * runs); - - ttl = ks_cpu_count() * 5; - //ttl = 5; - - - for(i = 0; i < runs; i++) { - ok(qtest1(size)); - ok(qtest2(ttl, 0, size) == 0); - ok(qtest2(ttl, 1, size) == 0); - ok(qtest2(ttl, 2, size) == 0); - } - - printf("TTL %d RUNS %d\n", ttl, runs); - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testq.vcxproj b/libs/libks/test/testq.vcxproj deleted file mode 100644 index 015c11a81f..0000000000 --- a/libs/libks/test/testq.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {3F8E0DF3-F402-40E0-8D78-44A094625D25} - Win32Proj - testq - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testrealloc.c b/libs/libks/test/testrealloc.c deleted file mode 100644 index 50c20a2bcb..0000000000 --- a/libs/libks/test/testrealloc.c +++ /dev/null @@ -1,40 +0,0 @@ -#include "ks.h" - -#include -#include -#include -#include "tap.h" - -int main(int argc, char **argv) -{ - ks_pool_t *pool; - uint32_t *buf = NULL; - intptr_t ptr = 0; - - ks_init(); - - plan(4); - - ks_pool_open(&pool); - - buf = (uint32_t *)ks_pool_alloc(pool, sizeof(uint32_t) * 1); - ok(buf != NULL); - - ptr = (intptr_t)buf; - - buf = (uint32_t *)ks_pool_resize(buf, sizeof(uint32_t) * 1); - ok(buf != NULL); - - ok((intptr_t)buf == ptr); - - buf = (uint32_t *)ks_pool_resize(buf, sizeof(uint32_t) * 2); - ok(buf != NULL); - - ks_pool_free(&buf); - - ks_pool_close(&pool); - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testrealloc.vcxproj b/libs/libks/test/testrealloc.vcxproj deleted file mode 100644 index 54d06df631..0000000000 --- a/libs/libks/test/testrealloc.vcxproj +++ /dev/null @@ -1,194 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {22BCE97F-2477-427D-83FE-74851DDBC57E} - Win32Proj - testrealloc - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testsock.c b/libs/libks/test/testsock.c deleted file mode 100644 index e17b9b6c50..0000000000 --- a/libs/libks/test/testsock.c +++ /dev/null @@ -1,412 +0,0 @@ -#include -#include - -static char v4[48] = ""; -static char v6[48] = ""; -static int mask = 0; -static int tcp_port = 8090; -static int udp_cl_port = 9090; -static int udp_sv_port = 9091; - -static char __MSG[] = "TESTING................................................................................/TESTING"; - -struct tcp_data { - ks_socket_t sock; - ks_sockaddr_t addr; - int ready; - char *ip; -}; - -void server_callback(ks_socket_t server_sock, ks_socket_t client_sock, ks_sockaddr_t *addr, void *user_data) -{ - //struct tcp_data *tcp_data = (struct tcp_data *) user_data; - char buf[8192] = ""; - ks_status_t status; - ks_size_t bytes; - - printf("TCP SERVER SOCK %d connection from %s:%u\n", (int)server_sock, addr->host, addr->port); - - do { - bytes = sizeof(buf);; - status = ks_socket_recv(client_sock, buf, &bytes); - if (status != KS_STATUS_SUCCESS) { - printf("TCP SERVER BAIL %s\n", strerror(ks_errno())); - break; - } - printf("TCP SERVER READ %ld bytes [%s]\n", (long)bytes, buf); - } while(zstr_buf(buf) || strcmp(buf, __MSG)); - - bytes = strlen(buf); - status = ks_socket_send(client_sock, buf, &bytes); - printf("TCP SERVER WRITE %ld bytes\n", (long)bytes); - - ks_socket_close(&client_sock); - - printf("TCP SERVER COMPLETE\n"); -} - - - -static void *tcp_sock_server(ks_thread_t *thread, void *thread_data) -{ - struct tcp_data *tcp_data = (struct tcp_data *) thread_data; - - tcp_data->ready = 1; - ks_listen_sock(tcp_data->sock, &tcp_data->addr, 0, server_callback, tcp_data); - - printf("TCP THREAD DONE\n"); - - return NULL; -} - -static int test_addr(int v) -{ - ks_sockaddr_t addr1, addr2, addr3, addr4, addr5; - - printf("TESTING ADDR v%d\n", v); - - if (v == 4) { - if (ks_addr_set(&addr1, "10.100.200.5", 2467, AF_INET) != KS_STATUS_SUCCESS) { - return 0; - } - - if (strcmp(addr1.host, "10.100.200.5")) { - return 0; - } - - if (ks_addr_set(&addr2, "10.100.200.5", 2467, AF_INET) != KS_STATUS_SUCCESS) { - return 0; - } - - if (ks_addr_set(&addr3, "10.100.200.5", 1234, AF_INET) != KS_STATUS_SUCCESS) { - return 0; - } - - if (ks_addr_set(&addr4, "10.199.200.5", 2467, AF_INET) != KS_STATUS_SUCCESS) { - return 0; - } - - } else { - if (ks_addr_set(&addr1, "1607:f418:1210::1", 2467, AF_INET6) != KS_STATUS_SUCCESS) { - return 0; - } - - if (strcmp(addr1.host, "1607:f418:1210::1")) { - return 0; - } - - if (ks_addr_set(&addr2, "1607:f418:1210::1", 2467, AF_INET6) != KS_STATUS_SUCCESS) { - return 0; - } - - if (ks_addr_set(&addr3, "1607:f418:1210::1", 1234, AF_INET6) != KS_STATUS_SUCCESS) { - return 0; - } - - if (ks_addr_set(&addr4, "1337:a118:1306::1", 2467, AF_INET6) != KS_STATUS_SUCCESS) { - return 0; - } - } - - - if (ks_addr_copy(&addr5, &addr4) != KS_STATUS_SUCCESS) { - return 0; - } - - if (!ks_addr_cmp(&addr1, &addr2)) { - return 0; - } - - if (ks_addr_cmp(&addr1, &addr3)) { - return 0; - } - - if (ks_addr_cmp(&addr1, &addr4)) { - return 0; - } - - if (!ks_addr_cmp(&addr4, &addr5)) { - return 0; - } - - if (ks_addr_cmp(&addr1, &addr5)) { - return 0; - } - - - return 1; -} - -static int test_tcp(char *ip) -{ - ks_thread_t *thread_p = NULL; - ks_pool_t *pool; - ks_sockaddr_t addr; - int family = AF_INET; - ks_socket_t cl_sock = KS_SOCK_INVALID; - char buf[8192] = ""; - struct tcp_data tcp_data = { 0 }; - int r = 1, sanity = 100; - - ks_pool_open(&pool); - - if (strchr(ip, ':')) { - family = AF_INET6; - } - - if (ks_addr_set(&tcp_data.addr, ip, tcp_port, family) != KS_STATUS_SUCCESS) { - r = 0; - printf("TCP CLIENT Can't set ADDR\n"); - goto end; - } - - if ((tcp_data.sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) { - r = 0; - printf("TCP CLIENT Can't create sock family %d\n", family); - goto end; - } - - ks_socket_option(tcp_data.sock, SO_REUSEADDR, KS_TRUE); - ks_socket_option(tcp_data.sock, TCP_NODELAY, KS_TRUE); - - tcp_data.ip = ip; - - ks_thread_create(&thread_p, tcp_sock_server, &tcp_data, pool); - - while(!tcp_data.ready && --sanity > 0) { - ks_sleep(10000); - } - - ks_addr_set(&addr, ip, tcp_port, family); - cl_sock = ks_socket_connect(SOCK_STREAM, IPPROTO_TCP, &addr); - - //int x; - - printf("TCP CLIENT SOCKET %d %s %d\n", (int)cl_sock, addr.host, addr.port); - - ks_size_t msglen = strlen(__MSG); - ks_socket_send(cl_sock, __MSG, &msglen); - printf("TCP CLIENT WRITE %d bytes\n", (int)msglen); - //x = write((int)cl_sock, __MSG, (unsigned)strlen(__MSG)); - //printf("TCP CLIENT WRITE %d bytes\n", x); - - msglen = sizeof(buf); - ks_socket_recv(cl_sock, buf, &msglen); - printf("TCP CLIENT READ %d bytes [%s]\n", (int)msglen, buf); - //x = read((int)cl_sock, buf, sizeof(buf)); - //printf("TCP CLIENT READ %d bytes [%s]\n", x, buf); - - end: - - if (tcp_data.sock != KS_SOCK_INVALID) { - ks_socket_shutdown(tcp_data.sock, 2); - ks_socket_close(&tcp_data.sock); - } - - if (thread_p) { - ks_thread_join(thread_p); - } - - ks_socket_close(&cl_sock); - - ks_pool_close(&pool); - - return r; -} - - -struct udp_data { - int ready; - char *ip; - ks_socket_t sv_sock; -}; - -static void *udp_sock_server(ks_thread_t *thread, void *thread_data) -{ - struct udp_data *udp_data = (struct udp_data *) thread_data; - int family = AF_INET; - ks_status_t status; - ks_sockaddr_t addr, remote_addr = KS_SA_INIT; - char buf[8192] = ""; - ks_size_t bytes; - - udp_data->sv_sock = KS_SOCK_INVALID; - - if (strchr(udp_data->ip, ':')) { - family = AF_INET6; - } - - ks_addr_set(&addr, udp_data->ip, udp_sv_port, family); - remote_addr.family = family; - - if ((udp_data->sv_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP)) == KS_SOCK_INVALID) { - printf("UDP SERVER SOCKET ERROR %s\n", strerror(ks_errno())); - goto end; - } - - ks_socket_option(udp_data->sv_sock, SO_REUSEADDR, KS_TRUE); - - if (ks_addr_bind(udp_data->sv_sock, &addr) != KS_STATUS_SUCCESS) { - printf("UDP SERVER BIND ERROR %s\n", strerror(ks_errno())); - goto end; - } - - udp_data->ready = 1; - - printf("UDP SERVER SOCKET %d %s %d\n", (int)(udp_data->sv_sock), addr.host, addr.port); - bytes = sizeof(buf); - if ((status = ks_socket_recvfrom(udp_data->sv_sock, buf, &bytes, &remote_addr)) != KS_STATUS_SUCCESS) { - printf("UDP SERVER RECVFROM ERR %s\n", strerror(ks_errno())); - goto end; - } - printf("UDP SERVER READ %ld bytes [%s]\n", (long)bytes, buf); - - if (strcmp(buf, __MSG)) { - printf("INVALID MESSAGE\n"); - goto end; - } - - printf("UDP SERVER WAIT 2 seconds to test nonblocking sockets\n"); - ks_sleep(2000000); - printf("UDP SERVER RESPOND TO %d %s %d\n", (int)(udp_data->sv_sock), remote_addr.host, remote_addr.port); - bytes = strlen(buf); - if ((status = ks_socket_sendto(udp_data->sv_sock, buf, &bytes, &remote_addr)) != KS_STATUS_SUCCESS) { - printf("UDP SERVER SENDTO ERR %s\n", strerror(ks_errno())); - goto end; - } - printf("UDP SERVER WRITE %ld bytes [%s]\n", (long)bytes, buf); - - - end: - - udp_data->ready = -1; - printf("UDP THREAD DONE\n"); - - ks_socket_close(&udp_data->sv_sock); - - return NULL; -} - - -static int test_udp(char *ip) -{ - ks_thread_t *thread_p = NULL; - ks_pool_t *pool; - ks_sockaddr_t addr, remote_addr; - int family = AF_INET; - ks_socket_t cl_sock = KS_SOCK_INVALID; - char buf[8192] = ""; - int r = 1, sanity = 100; - struct udp_data udp_data = { 0 }; - ks_size_t bytes = 0; - ks_status_t status; - - ks_pool_open(&pool); - - if (strchr(ip, ':')) { - family = AF_INET6; - } - - ks_addr_set(&addr, ip, udp_cl_port, family); - - if ((cl_sock = socket(family, SOCK_DGRAM, IPPROTO_UDP)) == KS_SOCK_INVALID) { - printf("UDP CLIENT SOCKET ERROR %s\n", strerror(ks_errno())); - r = 0; goto end; - } - - ks_socket_option(cl_sock, SO_REUSEADDR, KS_TRUE); - - if (ks_addr_bind(cl_sock, &addr) != KS_STATUS_SUCCESS) { - printf("UDP CLIENT BIND ERROR %s\n", strerror(ks_errno())); - r = 0; goto end; - } - - ks_addr_set(&remote_addr, ip, udp_sv_port, family); - - udp_data.ip = ip; - ks_thread_create(&thread_p, udp_sock_server, &udp_data, pool); - - while(!udp_data.ready && --sanity > 0) { - ks_sleep(10000); - } - - printf("UDP CLIENT SOCKET %d %s %d -> %s %d\n", (int)cl_sock, addr.host, addr.port, remote_addr.host, remote_addr.port); - - bytes = strlen(__MSG); - if ((status = ks_socket_sendto(cl_sock, __MSG, &bytes, &remote_addr)) != KS_STATUS_SUCCESS) { - printf("UDP CLIENT SENDTO ERR %s\n", strerror(ks_errno())); - r = 0; goto end; - } - - printf("UDP CLIENT WRITE %ld bytes\n", (long)bytes); - ks_socket_option(cl_sock, KS_SO_NONBLOCK, KS_TRUE); - - sanity = 300; - do { - status = ks_socket_recvfrom(cl_sock, buf, &bytes, &remote_addr); - - if (status == KS_STATUS_BREAK && --sanity > 0) { - if ((sanity % 50) == 0) printf("UDP CLIENT SLEEP NONBLOCKING\n"); - ks_sleep(10000); - } else if (status != KS_STATUS_SUCCESS) { - printf("UDP CLIENT RECVFROM ERR %s\n", strerror(ks_errno())); - r = 0; goto end; - } - } while(status != KS_STATUS_SUCCESS); - printf("UDP CLIENT READ %ld bytes\n", (long)bytes); - - end: - - if (thread_p) { - ks_thread_join(thread_p); - } - - if (udp_data.ready > 0 && udp_data.sv_sock && ks_socket_valid(udp_data.sv_sock)) { - ks_socket_shutdown(udp_data.sv_sock, 2); - ks_socket_close(&udp_data.sv_sock); - } - - - - ks_socket_close(&cl_sock); - - ks_pool_close(&pool); - - return r; -} - - -int main(void) -{ - int have_v4 = 0, have_v6 = 0; - - ks_init(); - - ks_find_local_ip(v4, sizeof(v4), &mask, AF_INET, NULL); - ks_find_local_ip(v6, sizeof(v6), NULL, AF_INET6, NULL); - - printf("IPS: v4: [%s] v6: [%s]\n", v4, v6); - - have_v4 = zstr_buf(v4) ? 0 : 1; - have_v6 = zstr_buf(v6) ? 0 : 1; - - plan((have_v4 * 3) + (have_v6 * 3) + 1); - - ok(have_v4 || have_v6); - - if (have_v4) { - ok(test_tcp(v4)); - ok(test_udp(v4)); - ok(test_addr(4)); - } - - if (have_v6) { - ok(test_tcp(v6)); - ok(test_udp(v6)); - ok(test_addr(6)); - } - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testsock.vcxproj b/libs/libks/test/testsock.vcxproj deleted file mode 100644 index 5923a6623f..0000000000 --- a/libs/libks/test/testsock.vcxproj +++ /dev/null @@ -1,187 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {5DC38E2B-0512-4140-8A1B-59952A5DC9CB} - Win32Proj - testsock - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(LibraryPath) - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - false - - - Console - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testsock2.c b/libs/libks/test/testsock2.c deleted file mode 100644 index e07eb28d7e..0000000000 --- a/libs/libks/test/testsock2.c +++ /dev/null @@ -1,20 +0,0 @@ -#include -#include - -int main(int argc, char *argv[]) -{ - char ip[80] = ""; - - ks_init(); - - if (argc > 1) { - ks_ip_route(ip, sizeof(ip), argv[1]); - printf("IPS [%s]\n", ip); - } else { - fprintf(stderr, "Missing arg \n"); - } - - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testthreadmutex.c b/libs/libks/test/testthreadmutex.c deleted file mode 100644 index 65bac5f109..0000000000 --- a/libs/libks/test/testthreadmutex.c +++ /dev/null @@ -1,349 +0,0 @@ -#include "ks.h" -#include "tap.h" -#define MAX_STUFF 200 - -static ks_thread_t *threads[MAX_STUFF]; -static ks_thread_t *thread_p; - -static ks_pool_t *pool; -static ks_mutex_t *mutex; -static ks_mutex_t *mutex_non_recursive; -static ks_rwl_t *rwlock; -static ks_cond_t *cond; -static int counter1 = 0; -static int counter2 = 0; -static int counter3 = 0; -static int counter4 = 0; -static int counter5 = 0; -static int counter6 = 0; -static int threadscount = 0; -static int cpu_count = 0; - -#define LOOP_COUNT 10000 - -static void *thread_priority(ks_thread_t *thread, void *data) -{ - while (KS_THREAD_IS_RUNNING(thread)) { - ks_sleep(100000); - } - - return NULL; -} - -static void *thread_test_cond_producer_func(ks_thread_t *thread, void *data) -{ - for (;;) { - ks_cond_lock(cond); - if (counter5 >= LOOP_COUNT) { - ks_cond_unlock(cond); - break; - } - counter5++; - if (counter6 == 0) { - ks_cond_signal(cond); - } - counter6++; - ks_cond_unlock(cond); - *((int *) data) += 1; - } - - return NULL; -} - -static void *thread_test_cond_consumer_func(ks_thread_t *thread, void *data) -{ - int i; - - for (i = 0; i < LOOP_COUNT; i++) { - ks_cond_lock(cond); - while (counter6 == 0) { - ks_cond_wait(cond); - } - counter6--; - ks_cond_unlock(cond); - } - return NULL; -} - -static void check_cond(void) -{ - int count[MAX_STUFF] = { 0 }; - int ttl = 0; - - ok( (ks_pool_open(&pool) == KS_STATUS_SUCCESS) ); - ok( (ks_cond_create(&cond, pool) == KS_STATUS_SUCCESS) ); - - int i; - for(i = 0; i < cpu_count; i++) { - ok( (ks_thread_create(&threads[i], thread_test_cond_producer_func, &count[i], pool) == KS_STATUS_SUCCESS) ); - } - ok( (ks_thread_create(&thread_p, thread_test_cond_consumer_func, NULL, pool) == KS_STATUS_SUCCESS) ); - ok( (ks_pool_close(&pool) == KS_STATUS_SUCCESS) ); - for(i = 0; i < cpu_count; i++) { - ttl += count[i]; - } - - ok( (ttl == LOOP_COUNT) ); -} - - -static void *thread_test_rwlock_func(ks_thread_t *thread, void *data) -{ - int loop = 1; - - while (1) - { - ks_rwl_read_lock(rwlock); - if (counter4 == LOOP_COUNT) { - loop = 0; - } - ks_rwl_read_unlock(rwlock); - - if (!loop) { - break; - } - - ks_rwl_write_lock(rwlock); - if (counter4 != LOOP_COUNT) { - counter4++; - } - ks_rwl_write_unlock(rwlock); - } - return NULL; -} - -static void check_rwl(void) -{ - ks_status_t status; - - ok( (ks_pool_open(&pool) == KS_STATUS_SUCCESS) ); - ok( (ks_rwl_create(&rwlock, pool) == KS_STATUS_SUCCESS) ); - ks_rwl_read_lock(rwlock); - status = ks_rwl_try_read_lock(rwlock); - ok( status == KS_STATUS_SUCCESS ); - if ( status == KS_STATUS_SUCCESS ) { - ks_rwl_read_unlock(rwlock); - } - ks_rwl_read_unlock(rwlock); - - int i; - for(i = 0; i < cpu_count; i++) { - ok( (ks_thread_create(&threads[i], thread_test_rwlock_func, NULL, pool) == KS_STATUS_SUCCESS) ); - } - - for(i = 0; i < cpu_count; i++) { - ks_thread_join(threads[i]); - } - - ok( (ks_pool_close(&pool) == KS_STATUS_SUCCESS) ); - ok( (counter4 == LOOP_COUNT) ); - -} - -static void *thread_test_function_cleanup(ks_thread_t *thread, void *data) -{ - int d = (int)(intptr_t)data; - - while (KS_THREAD_IS_RUNNING(thread)) { - ks_sleep(100000); - } - - if ( d == 1 ) { - ks_mutex_lock(mutex); - counter3++; - ks_mutex_unlock(mutex); - } - - return NULL; -} - -static void *thread_test_function_detatched(ks_thread_t *thread, void *data) -{ - int i; - int d = (int)(intptr_t)data; - - for (i = 0; i < LOOP_COUNT; i++) { - ks_mutex_lock(mutex); - if (d == 1) { - counter2++; - } - ks_mutex_unlock(mutex); - } - ks_mutex_lock(mutex); - threadscount++; - ks_mutex_unlock(mutex); - - return NULL; -} - -static void *thread_test_function_atatched(ks_thread_t *thread, void *data) -{ - int i; - int d = (int)(intptr_t)data; - void *mem, *last_mem = NULL; - - for (i = 0; i < LOOP_COUNT; i++) { - if (last_mem) { - ks_pool_free(&last_mem); - } - mem = ks_pool_alloc(ks_pool_get(thread), 1024); - last_mem = mem; - } - - for (i = 0; i < LOOP_COUNT; i++) { - ks_mutex_lock(mutex); - if (d == 1) { - counter1++; - } - ks_mutex_unlock(mutex); - } - - return NULL; -} - -static void create_threads_cleanup(void) -{ - void *d = (void *)(intptr_t)1; - int i; - for(i = 0; i < cpu_count; i++) { - ok( (ks_thread_create(&threads[i], thread_test_function_cleanup, d, pool) == KS_STATUS_SUCCESS) ); - } - -} - -static void create_threads_atatched(void) -{ - void *d = (void *)(intptr_t)1; - - int i; - for(i = 0; i < cpu_count; i++) { - ok( (ks_thread_create(&threads[i], thread_test_function_atatched, d, pool) == KS_STATUS_SUCCESS) ); - } -} - -static void create_threads_detatched(void) -{ - ks_status_t status; - void *d = (void *)(intptr_t)1; - - int i; - for(i = 0; i < cpu_count; i++) { - status = ks_thread_create_ex(&threads[i], thread_test_function_detatched, d, KS_THREAD_FLAG_DETACHED, KS_THREAD_DEFAULT_STACK, KS_PRI_NORMAL, pool); - ok( status == KS_STATUS_SUCCESS ); - } -} - -static void check_thread_priority(void) -{ - ks_status_t status; - void *d = (void *)(intptr_t)1; - - status = ks_thread_create_ex(&thread_p, thread_priority, d, KS_THREAD_FLAG_DETACHED, KS_THREAD_DEFAULT_STACK, KS_PRI_IMPORTANT, pool); - ok( status == KS_STATUS_SUCCESS ); - ks_sleep(100000); - todo("Add check to see if has permission to set thread priority\n"); - ok( ks_thread_priority(thread_p) == KS_PRI_IMPORTANT ); - end_todo; - - ks_pool_free(&thread_p); -} - -static void join_threads(void) -{ - int i; - for(i = 0; i < cpu_count; i++) { - ok( (KS_STATUS_SUCCESS == ks_thread_join(threads[i])) ); - } -} - -static void check_atatched(void) -{ - ok( counter1 == (LOOP_COUNT * cpu_count) ); -} - -static void check_detached(void) -{ - ok( counter2 == (LOOP_COUNT * cpu_count) ); -} - -static void create_pool(void) -{ - ok( (ks_pool_open(&pool) == KS_STATUS_SUCCESS) ); -} - -static void check_cleanup(void) -{ - ok( (counter3 == cpu_count) ); -} - -static void check_pool_close(void) -{ - ok( (ks_pool_close(&pool) == KS_STATUS_SUCCESS) ); -} - -static void create_mutex(void) -{ - ok( (ks_mutex_create(&mutex, KS_MUTEX_FLAG_DEFAULT, pool) == KS_STATUS_SUCCESS) ); -} - -static void create_mutex_non_recursive(void) -{ - ok( (ks_mutex_create(&mutex_non_recursive, KS_MUTEX_FLAG_NON_RECURSIVE, pool) == KS_STATUS_SUCCESS) ); -} - -static void test_recursive_mutex(void) -{ - ks_status_t status; - - ks_mutex_lock(mutex); - status = ks_mutex_trylock(mutex); - if (status == KS_STATUS_SUCCESS) { - ks_mutex_unlock(mutex); - } - ok(status == KS_STATUS_SUCCESS); - ks_mutex_unlock(mutex); -} - -static void test_non_recursive_mutex(void) -{ - ks_status_t status; - ks_mutex_lock(mutex_non_recursive); - status = ks_mutex_trylock(mutex_non_recursive); - if (status == KS_STATUS_SUCCESS) { - ks_mutex_unlock(mutex_non_recursive); - } - ok(status != KS_STATUS_SUCCESS); - ks_mutex_unlock(mutex_non_recursive); -} - - -int main(int argc, char **argv) -{ - ks_init(); - cpu_count = ks_cpu_count() * 4; - - plan(21 + cpu_count * 6); - - diag("Starting testing for %d tests\n", 21 + cpu_count * 6); - - create_pool(); - create_mutex(); - create_mutex_non_recursive(); - test_recursive_mutex(); - test_non_recursive_mutex(); - check_thread_priority(); - create_threads_atatched(); - join_threads(); - check_atatched(); - create_threads_detatched(); - while (threadscount != cpu_count) ks_sleep(1000000); - check_detached(); - create_threads_cleanup(); - check_pool_close(); - check_cleanup(); - check_rwl(); - check_cond(); - - ks_shutdown(); - done_testing(); -} diff --git a/libs/libks/test/testthreadmutex.vcxproj b/libs/libks/test/testthreadmutex.vcxproj deleted file mode 100644 index 1ebc9e3325..0000000000 --- a/libs/libks/test/testthreadmutex.vcxproj +++ /dev/null @@ -1,187 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {AE572500-7266-4692-ACA4-5E37B7B4409A} - Win32Proj - testthreadmutex - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - false - - - Console - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testtime.c b/libs/libks/test/testtime.c deleted file mode 100644 index 0b3a3c0467..0000000000 --- a/libs/libks/test/testtime.c +++ /dev/null @@ -1,45 +0,0 @@ -#include "ks.h" -#include "tap.h" - -int main(int argc, char **argv) -{ - int64_t now, then; - int diff; - int i; - - ks_init(); - - plan(2); - - then = ks_time_now(); - - ks_sleep(2000000); - - now = ks_time_now(); - - diff = (int)((now - then) / 1000); - printf("DIFF %ums\n", diff); - - - ok( diff > 1990 && diff < 2010 ); - - then = ks_time_now(); - - for (i = 0; i < 100; i++) { - ks_sleep(20000); - } - - now = ks_time_now(); - - diff = (int)((now - then) / 1000); - printf("DIFF %ums\n", diff); - -#if defined(__APPLE__) - /* the clock on osx seems to be particularly bad at being accurate, we need a bit more room for error*/ - ok( diff > 1900 && diff < 2100 ); -#else - ok( diff > 1950 && diff < 2050 ); -#endif - ks_shutdown(); - done_testing(); -} diff --git a/libs/libks/test/testtime.vcxproj b/libs/libks/test/testtime.vcxproj deleted file mode 100644 index 1a8b482f7c..0000000000 --- a/libs/libks/test/testtime.vcxproj +++ /dev/null @@ -1,190 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {B74812A1-C67D-4568-AF84-26CE2004D8BF} - Win32Proj - testtime - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - Debug - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/libks/test/testwebsock.c b/libs/libks/test/testwebsock.c deleted file mode 100644 index 798e87ecdb..0000000000 --- a/libs/libks/test/testwebsock.c +++ /dev/null @@ -1,287 +0,0 @@ -#include -#include - -#ifdef _WINDOWS_ -#undef unlink -#define unlink _unlink -#endif - -static char v4[48] = ""; -static char v6[48] = ""; -static int mask = 0; -static int tcp_port = 8090; - - -static char __MSG[] = "TESTING................................................................................/TESTING"; - - -typedef struct ssl_profile_s { - const SSL_METHOD *ssl_method; - SSL_CTX *ssl_ctx; - char cert[512]; - char key[512]; - char chain[512]; -} ssl_profile_t; - -static int init_ssl(ssl_profile_t *profile) -{ - const char *err = ""; - - profile->ssl_ctx = SSL_CTX_new(profile->ssl_method); /* create context */ - assert(profile->ssl_ctx); - - /* Disable SSLv2 */ - SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv2); - /* Disable SSLv3 */ - SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_SSLv3); - /* Disable TLSv1 */ - SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_TLSv1); - /* Disable Compression CRIME (Compression Ratio Info-leak Made Easy) */ - SSL_CTX_set_options(profile->ssl_ctx, SSL_OP_NO_COMPRESSION); - - /* set the local certificate from CertFile */ - if (!zstr(profile->chain)) { - if (!SSL_CTX_use_certificate_chain_file(profile->ssl_ctx, profile->chain)) { - err = "CERT CHAIN FILE ERROR"; - goto fail; - } - } - - if (!SSL_CTX_use_certificate_file(profile->ssl_ctx, profile->cert, SSL_FILETYPE_PEM)) { - err = "CERT FILE ERROR"; - goto fail; - } - - /* set the private key from KeyFile */ - - if (!SSL_CTX_use_PrivateKey_file(profile->ssl_ctx, profile->key, SSL_FILETYPE_PEM)) { - err = "PRIVATE KEY FILE ERROR"; - goto fail; - } - - /* verify private key */ - if ( !SSL_CTX_check_private_key(profile->ssl_ctx) ) { - err = "PRIVATE KEY FILE ERROR"; - goto fail; - } - - SSL_CTX_set_cipher_list(profile->ssl_ctx, "HIGH:!DSS:!aNULL@STRENGTH"); - - return 1; - - fail: - ks_log(KS_LOG_ERROR, "SSL ERR: %s\n", err); - - return 0; - -} - -struct tcp_data { - ks_socket_t sock; - ks_sockaddr_t addr; - int ready; - char *ip; - ks_pool_t *pool; - int ssl; - ssl_profile_t client_profile; - ssl_profile_t server_profile; -}; - -void server_callback(ks_socket_t server_sock, ks_socket_t client_sock, ks_sockaddr_t *addr, void *user_data) -{ - struct tcp_data *tcp_data = (struct tcp_data *) user_data; - ks_size_t bytes; - kws_t *kws = NULL; - kws_opcode_t oc; - uint8_t *data; - - - if (tcp_data->ssl) { - tcp_data->server_profile.ssl_method = SSLv23_server_method(); - ks_set_string(tcp_data->server_profile.cert, "./testwebsock.pem"); - ks_set_string(tcp_data->server_profile.key, "./testwebsock.pem"); - ks_set_string(tcp_data->server_profile.chain, "./testwebsock.pem"); - init_ssl(&tcp_data->server_profile); - } - - printf("WS %s SERVER SOCK %d connection from %s:%u\n", tcp_data->ssl ? "SSL" : "PLAIN", (int)server_sock, addr->host, addr->port); - - if (kws_init(&kws, client_sock, tcp_data->server_profile.ssl_ctx, NULL, KWS_BLOCK, tcp_data->pool) != KS_STATUS_SUCCESS) { - printf("WS SERVER CREATE FAIL\n"); - goto end; - } - - do { - - bytes = kws_read_frame(kws, &oc, &data); - - if (bytes <= 0) { - printf("WS SERVER BAIL %s\n", strerror(ks_errno())); - break; - } - printf("WS SERVER READ %ld bytes [%s]\n", (long)bytes, (char *)data); - } while(zstr_buf((char *)data) || strcmp((char *)data, __MSG)); - - bytes = kws_write_frame(kws, WSOC_TEXT, (char *)data, strlen((char *)data)); - - printf("WS SERVER WRITE %ld bytes\n", (long)bytes); - - end: - - ks_socket_close(&client_sock); - - kws_destroy(&kws); - - if (tcp_data->ssl) { - SSL_CTX_free(tcp_data->server_profile.ssl_ctx); - } - - printf("WS SERVER COMPLETE\n"); -} - - - -static void *tcp_sock_server(ks_thread_t *thread, void *thread_data) -{ - struct tcp_data *tcp_data = (struct tcp_data *) thread_data; - - tcp_data->ready = 1; - ks_listen_sock(tcp_data->sock, &tcp_data->addr, 0, server_callback, tcp_data); - - printf("WS THREAD DONE\n"); - - return NULL; -} - -static int test_ws(char *ip, int ssl) -{ - ks_thread_t *thread_p = NULL; - ks_pool_t *pool; - ks_sockaddr_t addr; - int family = AF_INET; - ks_socket_t cl_sock = KS_SOCK_INVALID; - struct tcp_data tcp_data = { 0 }; - int r = 1, sanity = 100; - kws_t *kws = NULL; - - ks_pool_open(&pool); - - tcp_data.pool = pool; - - if (ssl) { - tcp_data.ssl = 1; - tcp_data.client_profile.ssl_method = SSLv23_client_method(); - ks_set_string(tcp_data.client_profile.cert, "./testwebsock.pem"); - ks_set_string(tcp_data.client_profile.key, "./testwebsock.pem"); - ks_set_string(tcp_data.client_profile.chain, "./testwebsock.pem"); - init_ssl(&tcp_data.client_profile); - } - - - if (strchr(ip, ':')) { - family = AF_INET6; - } - - if (ks_addr_set(&tcp_data.addr, ip, tcp_port, family) != KS_STATUS_SUCCESS) { - r = 0; - printf("WS CLIENT Can't set ADDR\n"); - goto end; - } - - if ((tcp_data.sock = socket(family, SOCK_STREAM, IPPROTO_TCP)) == KS_SOCK_INVALID) { - r = 0; - printf("WS CLIENT Can't create sock family %d\n", family); - goto end; - } - - ks_socket_option(tcp_data.sock, SO_REUSEADDR, KS_TRUE); - ks_socket_option(tcp_data.sock, TCP_NODELAY, KS_TRUE); - - tcp_data.ip = ip; - - ks_thread_create(&thread_p, tcp_sock_server, &tcp_data, pool); - - while(!tcp_data.ready && --sanity > 0) { - ks_sleep(10000); - } - - ks_addr_set(&addr, ip, tcp_port, family); - cl_sock = ks_socket_connect(SOCK_STREAM, IPPROTO_TCP, &addr); - - printf("WS %s CLIENT SOCKET %d %s %d\n", ssl ? "SSL" : "PLAIN", (int)cl_sock, addr.host, addr.port); - - if (kws_init(&kws, cl_sock, tcp_data.client_profile.ssl_ctx, "/verto:tatooine.freeswitch.org:verto", KWS_BLOCK, pool) != KS_STATUS_SUCCESS) { - printf("WS CLIENT CREATE FAIL\n"); - goto end; - } - - kws_write_frame(kws, WSOC_TEXT, __MSG, strlen(__MSG)); - - kws_opcode_t oc; - uint8_t *data; - ks_ssize_t bytes; - - bytes = kws_read_frame(kws, &oc, &data); - printf("WS CLIENT READ %ld bytes [%s]\n", (long)bytes, (char *)data); - - end: - - kws_destroy(&kws); - - if (ssl) { - SSL_CTX_free(tcp_data.client_profile.ssl_ctx); - } - - if (tcp_data.sock != KS_SOCK_INVALID) { - ks_socket_shutdown(tcp_data.sock, 2); - ks_socket_close(&tcp_data.sock); - } - - if (thread_p) { - ks_thread_join(thread_p); - } - - ks_socket_close(&cl_sock); - - ks_pool_close(&pool); - - return r; -} - - - -int main(void) -{ - int have_v4 = 0, have_v6 = 0; - ks_find_local_ip(v4, sizeof(v4), &mask, AF_INET, NULL); - ks_find_local_ip(v6, sizeof(v6), NULL, AF_INET6, NULL); - ks_init(); - - printf("IPS: v4: [%s] v6: [%s]\n", v4, v6); - - have_v4 = zstr_buf(v4) ? 0 : 1; - have_v6 = zstr_buf(v6) ? 0 : 1; - - plan((have_v4 * 2) + (have_v6 * 2) + 1); - - ok(have_v4 || have_v6); - - if (have_v4 || have_v6) { - ks_gen_cert(".", "testwebsock.pem"); - } - - if (have_v4) { - ok(test_ws(v4, 0)); - ok(test_ws(v4, 1)); - } - - if (have_v6) { - ok(test_ws(v6, 0)); - ok(test_ws(v6, 1)); - } - - unlink("./testwebsock.pem"); - ks_shutdown(); - - done_testing(); -} diff --git a/libs/libks/test/testwebsock.vcxproj b/libs/libks/test/testwebsock.vcxproj deleted file mode 100644 index c4f44e2d61..0000000000 --- a/libs/libks/test/testwebsock.vcxproj +++ /dev/null @@ -1,194 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - {90D1C15C-59B0-470F-B18A-DA355948C736} - Win32Proj - testwebsock - 8.1 - - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - Application - true - v140 - Unicode - - - Application - false - v140 - true - Unicode - - - - - - - - - - - - - - - - - - - - - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - true - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir)$(Platform)\$(Configuration)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - false - $(Platform)\$(Configuration)\$(ProjectName)\ - $(SolutionDir);$(SolutionDir)\crypt;$(IncludePath) - $(LibraryPath) - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - - - Level3 - Disabled - _CRT_SECURE_NO_WARNINGS;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - false - - - Console - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - Level3 - - - MaxSpeed - true - true - _CRT_SECURE_NO_WARNINGS;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - true - ;.;%(AdditionalIncludeDirectories) - 4090 - true - - - Console - true - true - true - %(AdditionalDependencies) - - - - - {70d178d8-1100-4152-86c0-809a91cff832} - - - - - - - - - - \ No newline at end of file diff --git a/libs/win32/Download libconfig.2015.vcxproj b/libs/win32/Download libconfig.2015.vcxproj deleted file mode 100644 index 78ae395d30..0000000000 --- a/libs/win32/Download libconfig.2015.vcxproj +++ /dev/null @@ -1,85 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - Download libconfig - Download libconfig - Win32Proj - {4AB0A14F-F65F-4C18-AAEC-AC76E2BE07DA} - - - - Utility - MultiByte - v140 - - - Utility - MultiByte - v140 - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\libconfig\$(Configuration)\ - $(PlatformName)\libconfig\$(Configuration)\ - - - - $(IntDir)BuildLog $(ProjectName).htm - - - - - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - - - - - - - - - - - Document - Downloading libconfig. - if not exist "$(ProjectDir)..\libconfig-$(ConfigVersion)" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://files.freeswitch.org/downloads/libs/libconfig-$(ConfigVersion).7z "$(ProjectDir).." - - $(ProjectDir)..\libconfig-$(ConfigVersion);%(Outputs) - Downloading libconfig. - if not exist "$(ProjectDir)..\libconfig-$(ConfigVersion)" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://files.freeswitch.org/downloads/libs/libconfig-$(ConfigVersion).7z "$(ProjectDir).." - - $(ProjectDir)..\libconfig-$(ConfigVersion);%(Outputs) - - - - - - \ No newline at end of file diff --git a/libs/win32/Download libsodium.2015.vcxproj b/libs/win32/Download libsodium.2015.vcxproj deleted file mode 100644 index 6d2567c972..0000000000 --- a/libs/win32/Download libsodium.2015.vcxproj +++ /dev/null @@ -1,85 +0,0 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - - Download libsodium - Download libsodium - Win32Proj - {96848DD5-1451-4A88-87FA-FC6B7C7D1E1D} - - - - Utility - MultiByte - v140 - - - Utility - MultiByte - v140 - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - $(PlatformName)\libsodium\$(Configuration)\ - $(PlatformName)\libsodium\$(Configuration)\ - - - - $(IntDir)BuildLog $(ProjectName).htm - - - - - - - - - $(IntDir)BuildLog $(ProjectName).htm - - - - - - - - - - - - - Document - Downloading libsodium. - if not exist "$(ProjectDir)..\libsodium-$(sodiumVersion)" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://files.freeswitch.org/downloads/libs/libsodium-$(sodiumVersion).7z "$(ProjectDir).." - - $(ProjectDir)..\libsodium-$(sodiumVersion);%(Outputs) - Downloading libsodium. - if not exist "$(ProjectDir)..\libsodium-$(sodiumVersion)" cscript /nologo "$(ProjectDir)util.vbs" GetUnzip http://files.freeswitch.org/downloads/libs/libsodium-$(sodiumVersion).7z "$(ProjectDir).." - - $(ProjectDir)..\libsodium-$(sodiumVersion);%(Outputs) - - - - - - \ No newline at end of file diff --git a/libs/win32/libconfig/libconfig.2015.vcxproj b/libs/win32/libconfig/libconfig.2015.vcxproj deleted file mode 100644 index dd881d8bba..0000000000 --- a/libs/win32/libconfig/libconfig.2015.vcxproj +++ /dev/null @@ -1,350 +0,0 @@ - - - - - DebugDLL - Win32 - - - DebugDLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseDLL - Win32 - - - ReleaseDLL - x64 - - - Release - Win32 - - - Release - x64 - - - - libconfig - {1A234565-926D-49B2-83E4-D56E0C38C9F2} - Win32Proj - libconfig - - - - StaticLibrary - true - MultiByte - false - v140 - - - DynamicLibrary - true - MultiByte - false - v140 - - - StaticLibrary - true - MultiByte - false - v140 - - - DynamicLibrary - true - MultiByte - false - v140 - - - StaticLibrary - false - true - MultiByte - v140 - - - DynamicLibrary - false - true - MultiByte - v140 - - - StaticLibrary - false - true - MultiByte - v140 - - - DynamicLibrary - false - true - MultiByte - v140 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - true - - - false - - - false - - - false - - - false - - - - - - Level3 - Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebug - %(AdditionalIncludeDirectories) - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebugDLL - %(AdditionalIncludeDirectories) - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebugDLL - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - - - Level3 - Disabled - WIN32;_DEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebugDLL - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - Level3 - - - Full - true - true - WIN32;NDEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreaded - Speed - %(AdditionalIncludeDirectories) - false - /arch:AVX %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - - - Full - true - true - WIN32;NDEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDLL - Speed - %(AdditionalIncludeDirectories) - false - /arch:AVX %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDLL - false - /arch:AVX %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - WIN32;NDEBUG;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDLL - false - /arch:AVX %(AdditionalOptions) - - - Console - true - true - true - - - - - - - - - - - - - - - - - - - - - {4ab0a14f-f65f-4c18-aaec-ac76e2be07da} - - - - - - \ No newline at end of file diff --git a/libs/win32/libconfig/libconfig.2015.vcxproj.filters b/libs/win32/libconfig/libconfig.2015.vcxproj.filters deleted file mode 100644 index e7b884e6c6..0000000000 --- a/libs/win32/libconfig/libconfig.2015.vcxproj.filters +++ /dev/null @@ -1,57 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/libs/win32/libsodium/libsodium.2015.vcxproj b/libs/win32/libsodium/libsodium.2015.vcxproj deleted file mode 100644 index 9dbbfc3db0..0000000000 --- a/libs/win32/libsodium/libsodium.2015.vcxproj +++ /dev/null @@ -1,564 +0,0 @@ - - - - - DebugDLL - Win32 - - - DebugDLL - x64 - - - Debug - Win32 - - - Debug - x64 - - - ReleaseDLL - Win32 - - - ReleaseDLL - x64 - - - Release - Win32 - - - Release - x64 - - - - libsodium - {A185B162-6CB6-4502-B03F-B56F7699A8D9} - Win32Proj - libsodium - 8.1 - - - - StaticLibrary - true - MultiByte - false - v140 - - - DynamicLibrary - true - MultiByte - false - v140 - - - StaticLibrary - true - MultiByte - false - v140 - - - DynamicLibrary - true - MultiByte - false - v140 - - - StaticLibrary - false - true - MultiByte - v140 - - - DynamicLibrary - false - true - MultiByte - v140 - - - StaticLibrary - false - true - MultiByte - v140 - - - DynamicLibrary - false - false - MultiByte - v140 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - true - - - true - - - true - - - true - - - false - - - false - - - false - - - false - - - - - - Level3 - Disabled - SODIUM_STATIC;SODIUM_EXPORT=;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebug - %(AdditionalIncludeDirectories) - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - - - Level3 - Disabled - SODIUM_EXPORT=__declspec(dllexport);SODIUM_DLL_EXPORT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebugDLL - %(AdditionalIncludeDirectories) - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - - - Level3 - Disabled - SODIUM_STATIC;SODIUM_EXPORT=;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebugDLL - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - - - Level3 - Disabled - SODIUM_EXPORT=__declspec(dllexport);SODIUM_DLL_EXPORT;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDebugDLL - /arch:AVX %(AdditionalOptions) - false - - - Console - true - - - - - Level3 - - - Full - true - true - SODIUM_STATIC;SODIUM_EXPORT=;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreaded - Speed - %(AdditionalIncludeDirectories) - false - /arch:AVX %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - - - Full - true - true - SODIUM_EXPORT=__declspec(dllexport);SODIUM_DLL_EXPORT;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDLL - Speed - %(AdditionalIncludeDirectories) - false - /arch:AVX %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - SODIUM_STATIC;SODIUM_EXPORT=;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDLL - false - /arch:AVX %(AdditionalOptions) - - - Console - true - true - true - - - - - Level3 - - - MaxSpeed - true - true - SODIUM_EXPORT=__declspec(dllexport);SODIUM_DLL_EXPORT;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) - 4244;%(DisableSpecificWarnings) - MultiThreadedDLL - false - /arch:AVX %(AdditionalOptions) - true - - - Console - true - true - true - true - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - {96848dd5-1451-4a88-87fa-fc6b7c7d1e1d} - - - - - - \ No newline at end of file diff --git a/libs/win32/libsodium/libsodium.2015.vcxproj.filters b/libs/win32/libsodium/libsodium.2015.vcxproj.filters deleted file mode 100644 index 6998b0846f..0000000000 --- a/libs/win32/libsodium/libsodium.2015.vcxproj.filters +++ /dev/null @@ -1,690 +0,0 @@ - - - - - {4FC737F1-C7A5-4376-A066-2A32D752A2FF} - cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx - - - {93995380-89BD-4b04-88EB-625FBE52EBFB} - h;hpp;hxx;hm;inl;inc;xsd - - - {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} - rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms - - - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - Source Files - - - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - \ No newline at end of file diff --git a/w32/config.props b/w32/config.props deleted file mode 100644 index 52e60c1b03..0000000000 --- a/w32/config.props +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - true - - - - $(ProjectDir)..\..\libconfig-$(ConfigVersion)\lib;%(AdditionalIncludeDirectories) - true - LIBCONFIG_EXPORTS;YY_NO_UNISTD_H;YY_USE_CONST;%(PreprocessorDefinitions) - - - - diff --git a/w32/sodium.props b/w32/sodium.props deleted file mode 100644 index a5700a1882..0000000000 --- a/w32/sodium.props +++ /dev/null @@ -1,20 +0,0 @@ - - - - - - - - true - - - - $(ProjectDir)..\..\libsodium-$(SodiumVersion)\src\libsodium\include\sodium;%(AdditionalIncludeDirectories) - true - UNICODE;_UNICODE;%(PreprocessorDefinitions) - NATIVE_LITTLE_ENDIAN=1;%(PreprocessorDefinitions) - inline=__inline;%(PreprocessorDefinitions) - - - -